线段树+动态开点+区间更新
题目链接:http://poj.org/problem?id=2528
题目大意:贴海报,后面的海报会覆盖前面的海报。问最后还能看见几张海报。
1 <= n <= 10000
1 <= i <= n, 1 <= li <= ri <= 10000000
样例解释:
思路:普通做法:离散化+add标记,更新如果没有在本区间,并且本标记的add!=0,把标记下推,最后统计不同add的数量。
动态建点就可以不用离散化。直接用到哪个建哪个。20倍空间好像没有够用,开了200倍。。。
#include<bits/stdc++.h>
#define mid (l+r)/2
using namespace std;
int L[2000000]={0}, R[2000000]={0}, sum[2000000]={0};
int tot=1;
int build()
{
++tot;
L[tot]=R[tot]=sum[tot]=0;
return tot;
}
int qdata(int p, int l, int r, int LL, int RR, int v)//区间更新
{
if(LL==l&&RR==r)
{
sum[p]=v;
return 0;
}
if(RR<=mid)
{
if(!L[p])
{
L[p]=build();
}
if(!R[p])
{
R[p]=build();
}
if(sum[p])//把标记下推
{
sum[L[p]]=sum[p];
sum[R[p]]=sum[p];
sum[p]=0;
}
qdata(L[p], l, mid, LL, RR, v);
}
else if(LL>=mid+1)
{
if(!L[p])
{
L[p]=build();
}
if(!R[p])
{
R[p]=build();
}
if(sum[p])//把标记下推
{
sum[L[p]]=sum[p];
sum[R[p]]=sum[p];
sum[p]=0;
}
qdata(R[p], mid+1, r, LL, RR, v);
}
else
{
if(!L[p])
{
L[p]=build();
}
if(!R[p])
{
R[p]=build();
}
if(sum[p])//把标记下推
{
sum[L[p]]=sum[p];
sum[R[p]]=sum[p];
sum[p]=0;
}
qdata(L[p], l, mid, LL, mid, v);
qdata(R[p], mid+1, r, mid+1, RR, v);
}
}
set<int> s;
int cx(int p, int l, int r, int LL, int RR)
{
if(sum[p]||p==0)//有标记或者这个区间没有海报(没有海报就没有更新就动态建点p=0)
{
if(sum[p])
{
s.insert(sum[p]);
}
return 0;
}
if(RR<=mid)
{
cx(L[p], l, mid, LL, RR);
}
else if(LL>=mid+1)
{
cx(R[p], mid+1, r, LL, RR);
}
else
{
cx(L[p], l, mid, LL, mid);
cx(R[p], mid+1, r, mid+1, RR);
}
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
s.clear();
tot=1;
memset(L, 0, sizeof(L));
memset(R, 0, sizeof(R));
memset(sum, 0, sizeof(sum));
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
int k, v;
scanf("%d %d",&k,&v);
qdata(1, 1, 10000000, k, v, i);
}
cx(1, 1, 10000000, 1, 10000000);
cout<<s.size()<<endl;
}
return 0;
}