poj 2528 Mayor's posters(线段树,离散化)
题目链接:http://poj.org/problem?id=2528
第一次写这么长的代码...
题意:
有一长为107的区间,给n个区间染色,问最后可以看到几种颜色。(1≤n≤104)
思路:
区间问题比较适合用线段树处理,因为区间较大,需要将端点离散化集中起来减小内存开支。
Tips:
stdio是79MS,iostream是625MS。
#include <iostream>//cin cout #include <cstring>//memset #include <algorithm>//sort using namespace std; const int M=22000; int tree[M<<4];//完全二叉树存储线段树 int lf[M],rt[M];//存储输入区间左右端点 int ls[3*M];//存储离散化后的新端点 int vis[3*M];//该颜色是否已计入答案 void pushdown(int p) { tree[p<<1]=tree[(p<<1)|1]=tree[p]; tree[p]=-1; } void update(int p,int l,int r,int x,int y,int v)//给p点l~r区间内的x~y区间染上v色 { if(x<=l&&y>=r)//如果该区间被x~y完全覆盖,染上v色 { tree[p]=v; return; } if(tree[p]!=-1) pushdown(p);//若原区间不能被x~y完全覆盖且已染色,将原区间颜色推至子区间,原区间颜色置空 int mid=(l+r)>>1; if(y<=mid) update(p<<1,l,mid,x,y,v);//两区间关系分情况讨论,继续为子区间染色 else if(x>mid) update((p<<1)|1,mid+1,r,x,y,v); else update(p<<1,l,mid,x,mid,v),update((p<<1)|1,mid+1,r,mid+1,y,v); } int query(int p,int l,int r)//从p点开始下查l~r区间有多少种颜色 { if(tree[p]!=-1)//如果该区间已被染色,若是第一次计算该颜色返回1 return vis[tree[p]]++==0; if(l==r)//如果已访问到底部端点 return 0; int mid=(l+r)>>1;//如果该区间染色状况不明,继续向下访问子区间 return query(p<<1,l,mid) + query((p<<1)|1,mid+1,r); } int main() { int t;cin>>t; while(t--) { int n;cin>>n; memset(tree,-1,sizeof(tree));//标记为未染色 memset(vis,false,sizeof(vis)); int len=0; for(int i=0;i<n;i++)//存储输入区间左右端点 { cin>>lf[i]>>rt[i]; ls[len++]=lf[i]; ls[len++]=rt[i]; } sort(ls,ls+len); int len2=unique(ls,ls+len)-ls;//离散化,排序 int t=len2; for(int i=1;i<t;i++) { if(ls[i]-ls[i-1]>1)//如果有区间长度大于2,插入一个端点,防止类似于(1,10)(1,4)(4,6)的情况 ls[len2++]=ls[i-1]+1; } sort(ls,ls+len2); for(int i=0;i<n;i++)//x,y为离散化后原端点的映射端点 { int x=lower_bound(ls,ls+len2,lf[i])-ls+1; int y=lower_bound(ls,ls+len2,rt[i])-ls+1; update(1,1,len2,x,y,i); } cout<<query(1,1,len2)<<"\n"; } return 0; }