POJ 2528 Mayor's posters(线段树,离散化,区间染色问题变形)

由于这面墙的长度是1e7,所给的范围太大,如果直接建树回超内存,所以考虑用离散化,因为这里只有10000个人,就算是每个人的海报都不相交,最多也就只会用2*n个点;
离散化详解

离散化过后的问题实际上就变成了了区间染色的问题(区间染色问题可以看这个大佬的博客讲的很详细),最开始墙没有贴海报,这里就把lazy全部标记为0,然后区间更新,如果这个区间贴有海报c,就把这个区间的lazy更新为c,全部更新完了之后,我们就可以直接查询区间lazy不等于1的个数,考虑到有重复的情况,所以这里我们直接把lazy放进set里面,最后set的元素个数就是我们要照的答案了

#include <iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<climits>
#include<vector>
#include<queue>
#include<string>
#include <cmath>
#include<set>
#define mod 999997
#define lson l, mid, root << 1
#define rson mid + 1, r, root << 1 | 1
#define father  l , r , root
#define lowbit(x) ( x & ( - x ) )
using namespace std;
typedef long long ll;
const int maxn = 20010;
const int inf = 0x3f3f3f3f;

int lazy[maxn<<4];
int ql[maxn],qr[maxn];
int all[maxn<<2];
int len;
int n;
int cnt;

set<int>q;

void lisan(){//离散化

    sort(all+1,all+1+cnt);
    len=unique(all+1,all+1+cnt)-all-1;
    for(int i=1;i<=n;i++){
        ql[i]=lower_bound(all+1,all+1+len,ql[i])-all;
        qr[i]=lower_bound(all+1,all+1+len,qr[i])-all;
    }
}

void push_down(int root){

    if(lazy[root]==0)   return ;

    lazy[root<<1]=lazy[root];
    lazy[root<<1|1]=lazy[root];
    lazy[root]=0;

}

void change(int L,int R,int val,int l,int r,int root){

    if(L<=l&&R>=r){
        lazy[root]=val;
        return ;
    }

    push_down(root);//这里如果是第一次改动是没有影响的,但如果是第二次改动,就应该吧这个节点再往下移动

    int mid=(l+r)>>1;
    if(mid>=L)change(L,R,val,lson);
    if(mid<R)change(L,R,val,rson);

}

void query(int l,int r,int root){

    if(lazy[root]!=0){
        q.insert(lazy[root]);
        return ;
    }

    if(l==r)    return ;//叶子结点

    push_down(root);

    int mid=(l+r)>>1;
    query(lson);
    query(rson);

}

int main( ){
   int t;
   scanf("%d",&t);
   while(t--){
        q.clear();
        memset(lazy,0,sizeof(lazy));//初始化
        scanf("%d",&n);
        cnt=0;//不要忘了初始化
        for(int i=1;i<=n;i++){
            scanf("%d%d",&ql[i],&qr[i]);
            all[++cnt]=ql[i];
            all[++cnt]=qr[i];
        }
        lisan();//离散化
        for(int i=1;i<=n;i++){
            change(ql[i],qr[i],i,1,len,1);
        }//区间更新
        query(1,len,1);
   printf("%d\n",q.size());
   }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值