Count the Colors ZOJ - 1610 (线段树)

一个非常有意思的区间染色问题,使用线段树的途中还有一些有趣的操作。

  1. 首先颜色可以从0开始;
  2. 这段区间是固定8000的;
  3. 染色点可以转化为左开右闭的染色区间;
  4. 题目只有一次查询,但需要按序查询全部;
  5. 仔细研究查询的代码,可以了解到线段树建立的过程其实是怎样的一个递归过程。
 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 }
View Code

 

posted @ 2019-08-02 10:52  然墨  阅读(164)  评论(0编辑  收藏  举报