Count the Colors ZOJ - 1610 (线段树)
一个非常有意思的区间染色问题,使用线段树的途中还有一些有趣的操作。
- 首先颜色可以从0开始;
- 这段区间是固定8000的;
- 染色点可以转化为左开右闭的染色区间;
- 题目只有一次查询,但需要按序查询全部;
- 仔细研究查询的代码,可以了解到线段树建立的过程其实是怎样的一个递归过程。
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<queue> 5 #define ll long long 6 #define inf 0x3f3f3f3f 7 using namespace std; 8 const int maxn=8008; 9 int t[maxn<<2]; 10 int ans[maxn]; 11 int n,x,y,z,last; 12 void init() 13 { 14 memset(t,-1,sizeof(t)); 15 memset(ans,0,sizeof(ans)); 16 } 17 void pushdown(int p) 18 { 19 if(t[p]==-1) return; 20 t[p<<1]=t[p<<1|1]=t[p]; 21 t[p]=-1; 22 } 23 void update(int l,int r,int p,int L,int R,int x) //l,r是目标段,L,R是当前段 24 { 25 if(l<=L&&R<=r) { 26 t[p]=x; 27 return; 28 } 29 if(t[p]==x) return; 30 pushdown(p); 31 int m=(L+R)>>1; 32 if(l<=m) update(l,r,p<<1,L,m,x); 33 if(r>m) update(l,r,p<<1|1,m+1,R,x); 34 } 35 void getans(int l,int r,int p) 36 { 37 if(l==r) 38 { 39 if(t[p]!=-1&&t[p]!=last) ans[t[p]]++; 40 last=t[p]; 41 return ; 42 } 43 pushdown(p); 44 int m=(l+r)>>1; 45 getans(l,m,p<<1); 46 getans(m+1,r,p<<1|1); 47 } 48 int main() 49 { 50 while(scanf("%d",&n)!=EOF) 51 { 52 init(); 53 while(n--) 54 { 55 scanf("%d%d%d",&x,&y,&z); 56 update(x+1,y,1,1,8000,z); 57 } 58 last=-1; 59 getans(1,8000,1); 60 for(int i=0;i<maxn;i++) if(ans[i]) cout<<i<<' '<<ans[i]<<endl; 61 cout<<endl; 62 } 63 return 0; 64 }