题目链接:https://vjudge.net/problem/POJ-2528
题意:在区间[1,1e7]内染色,依次染n(<=1e4)中颜色,给出每种颜色染色的范围,可重叠,求最终有多少种颜色。
思路:继续肝线段树。。被这题虐了一下午加一晚上QAQ。
首先要想到离散化,因为区间为1e7,直接做的话时间空间都做不到。但因为是区间,这里不能简单的离散化,比如1、5离散化为1、2是有问题的,必须离散化为1,3,5; 还记得要先去重。
其次是线段树,这道题是典型的线段树的题,直接对点操作的话复杂度很大,所以用线段树完成对区间的操作。线段树结点包括l(区间左端点)、r(区间右端点)、value(为0表示该区间没有颜色或有多种颜色,为>0表示对应的颜色编号)。
最后进行一次询问即可,仅当区间的value>0时再判断颜色,并且用hash数组记录颜色i是否出现过。
AC代码:
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int maxn=10005; struct node{ int l,r,value; }tr[16*maxn]; int a[maxn][2],b[4*maxn],T,n,hash[maxn],ans; void build(int v,int l, int r){ tr[v].l=l,tr[v].r=r,tr[v].value=0; if(l==r) return; int mid=(l+r)>>1; build(v<<1,l,mid); build(v<<1|1,mid+1,r); } void pushdown(int v){ tr[v<<1].value=tr[v].value; tr[v<<1|1].value=tr[v].value; tr[v].value=0; } void update(int v,int l,int r,int k){ if(l<=tr[v].l&&r>=tr[v].r){ tr[v].value=k; return; } if(tr[v].value) pushdown(v); int mid=(tr[v].l+tr[v].r)>>1; if(l<=mid) update(v<<1,l,r,k); if(r>mid) update(v<<1|1,l,r,k); } void query(int v){ if(tr[v].value){ if(!hash[tr[v].value]){ ++ans; hash[tr[v].value]=1; } return; } if(tr[v].l==tr[v].r) return; query(v<<1); query(v<<1|1); } int main(){ scanf("%d",&T); while(T--){ memset(hash,0,sizeof(hash)); ans=0; scanf("%d",&n); int cnt1=0; for(int i=1;i<=n;++i){ scanf("%d%d",&a[i][0],&a[i][1]); b[++cnt1]=a[i][0]; b[++cnt1]=a[i][1]; } sort(b+1,b+cnt1+1); int cnt2=1; for(int i=2;i<=cnt1;++i) if(b[i]!=b[i-1]) b[++cnt2]=b[i]; int t=cnt2; for(int i=2;i<=t;++i) if(b[i]-b[i-1]>1) b[++cnt2]=b[i-1]+1; sort(b+1,b+cnt2+1); build(1,1,cnt2); for(int i=1;i<=n;++i){ int x=lower_bound(b+1,b+cnt2+1,a[i][0])-b; int y=lower_bound(b+1,b+cnt2+1,a[i][1])-b; update(1,x,y,i); } query(1); printf("%d\n",ans); } return 0; }