HDU-5124,POJ-2528(线段树+离散化)

本文深入探讨了线段树算法的应用,通过两个具体问题——求相交区间的最大相交次数和统计墙上不同颜色海报的数量,详细介绍了线段树的实现细节和优化技巧。文章提供了完整的代码示例,帮助读者理解如何利用线段树解决区间更新和查询问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接: lines

题意

求相交区间的最大的相交次数。

思路

先离散化处理,再用线段树求每段区间的相交次数,这个线段树的每个节点代表这段区间的总相交次数,最后再比较每个小区间的相交次数,找最大值。

#include <bits/stdc++.h>
using namespace std;
const int maxn=50001;
int addmark[maxn<<3],seqtree[maxn<<3],miner;
void pushdown(int node,int begin,int end)
{
    int mid=(begin+end)/2;
    if(!addmark[node])
        return;
    addmark[node<<1]+=addmark[node];
    addmark[node<<1|1]+=addmark[node];
    seqtree[node<<1]+=addmark[node]*(mid-begin+1);
    seqtree[node<<1|1]+=addmark[node]*(end-mid);
    addmark[node]=0;
}
void update(int node,int begin,int end,int l,int r,int k)
{
    if(l>end || r<begin)
        return;
    if(l<=begin && r>=end)
    {
        seqtree[node]+=k*(end-begin+1);
        addmark[node]+=k;
        return;
    }
    pushdown(node,begin,end);
    int mid=(begin+end)/2;
    update(node<<1,begin,mid,l,r,k);
    update(node<<1|1,mid+1,end,l,r,k);
    seqtree[node]=seqtree[node<<1]+seqtree[node<<1|1];
}
void query(int node,int begin,int end,int l,int r)
{
   if(begin==end)
   {
       if(seqtree[node]>miner)
       {
           miner=seqtree[node];
       }
       return;
   }
    pushdown(node,begin,end);
    int mid=(begin+end)/2;
    query(node<<1,begin,mid,l,r);
    query(node<<1|1,mid+1,end,l,r);
}
int main()
{
    int p,t,i,n,a[maxn],b[maxn],lisan[4*maxn];
    cin.tie(0);
    ios::sync_with_stdio(0);
    cin>>p;
    while(p--)
    {
        miner=-1;
        cin>>n;
        int tot=0;
        for(i=0;i<n;i++)
        {
            cin>>a[i]>>b[i];
            lisan[tot++]=a[i];
            lisan[tot++]=b[i];
        }
        sort(lisan,lisan+tot);
        int m=unique(lisan,lisan+tot)-lisan;
        t=m;
        for(i=0;i<t-1;i++)
        {
            if(lisan[i+1]-lisan[i]>1)
                lisan[m++]=lisan[i]+1;
        }
        sort(lisan,lisan+m);
        memset(seqtree,0,sizeof(seqtree));
        memset(addmark,0,sizeof(addmark));
        for(i=0;i<n;i++)
        {
            int l=lower_bound(lisan,lisan+m,a[i])-lisan;
            int r=lower_bound(lisan,lisan+m,b[i])-lisan;
            update(1,0,m-1,l,r,1);
        }
        query(1,0,m-1,0,m-1);
        printf("%d\n",miner);
    }
}

题目链接: Mayor’s posters

题意

贴n张海报,每个海报有不同的颜色,占据一定区间,后来的海报可能会遮挡原来的海报,问最后墙上有几种颜色

思路

我强力怀疑题中的数据范围,因为数组的原因WA,RE到怀疑人生,这个题的线段树还有些不同于一般的线段树,一般线段树的节点代表这段区间的最大值或最小值或者是和,如果需要区间更新,需要用到延迟数组,这道题只用一个seqtree[]数组即可,不需要延迟数组,因为每个节点代表这段区间的此时的值,同时也可以代替延迟数组往下更新。query函数也不太一样,我们遍历整棵树,看看共有多少个不同的数字就代表有几种颜色。

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int maxn=20100;
int ans,vis[4*maxn],seqtree[maxn<<4],addmark[maxn<<4];
void pushdown(int node)
{
    if(seqtree[node]!=-1)
    {
        seqtree[node<<1]=seqtree[node<<1|1]=seqtree[node];
        seqtree[node]=-1;
    }
}
void update(int node,int begin,int end,int l,int r,int k)
{
    if(l>end || r<begin)
        return;
    if(l<=begin && r>=end)
    {
        seqtree[node]=k;
        return;
    }
    pushdown(node);
    int mid=(begin+end)/2;
    update(node<<1,begin,mid,l,r,k);
    update(node<<1|1,mid+1,end,l,r,k);
}
void query(int node,int begin,int end,int l,int r)
{
    if(seqtree[node]!=-1)
    {
        if(!vis[seqtree[node]])
        {
            vis[seqtree[node]]=1;
            ans++;
        }
    }
    if(begin==end)
        return;
    pushdown(node);
    int mid=(begin+end)/2;
    query(node<<1,begin,mid,l,r);
    query(node<<1|1,mid+1,end,l,r);
}
int main()
{
    int p,tot,n,a[maxn*4],b[maxn*4],lisan[8*maxn],t,i;
    cin>>p;
    while(p--)
    {
        t=0;
        cin>>n;
        for(i=0;i<n;i++)
        {
            cin>>a[i]>>b[i];
            lisan[tot++]=a[i];
            lisan[tot++]=b[i];
        }
        sort(lisan,lisan+tot);
        int m=unique(lisan,lisan+tot)-lisan;
        t=m;
        for(i=0;i<t-1;i++)
        {
            if(lisan[i+1]-lisan[i]>1)
            lisan[m++]=lisan[i]+1;
        }
        sort(lisan,lisan+m);
        memset(seqtree,-1,sizeof(seqtree));
        memset(vis,0,sizeof(vis));
        for(i=0;i<n;i++)
        {
            int l=lower_bound(lisan,lisan+m,a[i])-lisan;
            int r=lower_bound(lisan,lisan+m,b[i])-lisan;
            update(1,0,m-1,l,r,i);
        }
        ans=0;
        query(1,0,m-1,0,m-1);
        cout<<ans<<endl;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值