ZOJ 1610 Count the Colors
经典的线段上色问题,略有不同的地方时从0开始,还有要输出每种颜色的个数 。
题目:线段染色问题,求最后最上面的颜色段数
思路:对每一次染色执行update操作,当颜色未完全覆盖当前段时,当前根的颜色块需要下移!然后执行一次query操作记录所有线段的颜色
法一:
1 #include<stdio.h> 2 #include<string.h> 3 #define N 8001 4 int color[N],cnt[N];//这个cnt是用来记录颜色i出现的段数 ,注意cnt里的这个N真的需要好大,我以为就几百种呢,结果WA好多次 5 int main() 6 { 7 int i,j,a,b,c,max,n; 8 while(~scanf("%d",&n)){ 9 for(max=i=0;i<n;++i){ 10 scanf("%d%d%d",&a,&b,&c); 11 for(j=a;j<b;++j) 12 color[j]=c+1; 13 if(max<b) max=b; 14 } 15 for(i=0;i<max;++i){ 16 while(i!=0&&color[i]&&color[i]==color[i-1]) //假如颜色不为空且与前一段相同,则继续读下一段 17 ++i; 18 if(color[i]) 19 cnt[color[i]-1]++; //颜色为color[i]-1的段数加一 20 } 21 for(i=0;i<N;++i) 22 if(cnt[i]) printf("%d %d\n",i,cnt[i]);//从小到大输出颜色及出现次数 23 memset(color,0,max*sizeof(int));//记得清空 24 memset(cnt,0,sizeof(cnt)); 25 putchar('\n'); 26 } 27 return 0; 28 }
法二:
1。创建线段树
1)取最小和最大的两个数作为端点,建立线段树
2)当前节点的两个端点值之差等于一时,此时该节点即位叶子节点,不用再 向下分
3)否则,分裂该节点为[a,(a + b) / 2], [(a + b) / 2, b];
4)创建线段树时,注意初始化操作
2。线段树着色(根据不同的题目此操作各不相同,对zju_1610做分析)
1)当前节点的颜色与将要涂的颜色color相同,直接return
2)当前线段树节点的两个端点和要涂的两个端点正好都相同,则将该节点着为color,然后return
3)要涂的两个端点在当前节点的两个端点之间时:先将当前节点的颜色向其子节点扩展,然后:
1.要涂的右端点小于或等于当前节点middle = (a + b) / 2时,向左子节点移动
2.要涂的左端点大于或等于当前节点middle = (a + b) / 2时,向右子节点移动
3.else (1 ,2)向左右子节点移动
3。相关统计
1)当前节点未着色或其颜色与要统计的颜色不相同,直接return
2)从0——8000依次扫描,如果还是原来的数,即还是一条颜色,那么 continue,不计,是其他颜色,ans[c]++;
1 #include <iostream> 2 #include <string> 3 using namespace std; 4 #define MAX 8000 5 struct Node 6 { 7 int l,r; 8 int c; 9 }; 10 Node tree[MAX*4]; 11 int ans[MAX+10]; 12 int seg[MAX+10]; 13 void Initial(int i,int l, int r,int c) 14 { 15 if(l>=r ) 16 return; 17 tree[i].l = l; 18 tree[i].r = r; 19 tree[i].c = c; 20 if(r - l == 1) 21 return; 22 int mid = (tree[i].l+tree[i].r) >> 1; 23 Initial(i*2,l,mid,c); 24 Initial(i*2+1,mid,r,c); 25 } 26 void add(int i,int l,int r,int c) 27 { 28 if(c == tree[i].c) 29 { 30 return ; 31 } 32 if(l == tree[i].l && r == tree[i].r) 33 { 34 tree[i].c = c; 35 36 }else 37 { 38 int mid = (tree[i].l + tree[i].r) >> 1; 39 if(tree[i].c >= 0) 40 { 41 tree[i*2].c = tree[i].c; 42 tree[i*2+1].c = tree[i].c; 43 } 44 tree[i].c = -1; 45 if(l >= mid) 46 { 47 add(i*2+1,l,r,c); 48 } 49 else 50 if(r <= mid) 51 { 52 add(i*2,l,r,c); 53 }else 54 { 55 56 add(i*2,l,mid,c); 57 add(i*2+1,mid,r,c); 58 } 59 if(tree[i*2].c == tree[i*2+1].c) 60 { 61 tree[i].c = tree[i*2].c; 62 } 63 } 64 } 65 void counts(int i) 66 { 67 if(tree[i].c != -1) 68 { 69 for(int j = tree[i].l; j <= tree[i].r;j++) 70 { 71 seg[j] = tree[i].c; 72 } 73 } 74 else 75 { 76 counts(i*2); 77 counts(i*2+1); 78 } 79 } 80 void total() 81 { 82 int c = seg[0]; 83 for(int i = 0;i <= MAX;i++) 84 { 85 if(seg[i]==c) 86 continue; 87 if(c >= 0) ans[c] ++; 88 c= seg[i]; 89 90 } 91 if(c >= 0) ans[c] ++; 92 } 93 int main() { 94 freopen("in","r",stdin); 95 int i,n,x,y,c; 96 97 while(scanf("%d",&n) != EOF) 98 { 99 Initial(1,0,MAX,-2); 100 memset(ans,0,sizeof(ans)); 101 102 while(n--) 103 { 104 scanf("%d %d %d",&x,&y,&c); 105 add(1,x,y,c); 106 } 107 counts(1); 108 total(); 109 for(i = 0; i <= MAX; i++) 110 { 111 if(ans[i]) 112 { 113 printf("%d %d/n",i,ans[i]); 114 } 115 } 116 printf("/n"); 117 } 118 return 0; 119 }