用线段树统计染色问题。题意是每次把一个区间的一段区域染上某个色,统计任意区间内有多少种颜色。这题我借鉴了罗前辈的思路,用int型按位记录一个区间内的颜色,修改和查询都是从结点开始,递归操作子区间。不过我最自豪的是,我略加修改了一下,使得我这个线段树不需要建树也能运行,当成功A了以后我特别爽。为什么不建树也行呢?建树本质上就是初始化,而我的代码里tree[1] = 1和向下传递这两个部分已经完成了初始化的任务,也就是说build()被内嵌到change()里面去了。所以即使没有表面上的建树,依然能正确运行。
1 #include <stdio.h> 2 #include <string.h> 3 const int N = 100010; 4 int tree[N<<2]; 5 inline bool single(int a) 6 { 7 return !( (a-1)& a); 8 } 9 void change(int u,int x,int y,int s,int t,int n) 10 { 11 int mid = (x+y)>>1,lc = u<<1,rc = lc|1; 12 if(s <= x && y <= t) 13 { 14 tree[u] = 1 << (n-1); 15 return ; 16 } 17 if(tree[u] == 1<<(n-1) )return ; 18 if(single(tree[u])) 19 tree[lc] = tree[rc] = tree[u]; 20 if(s <= mid) 21 change(lc,x,mid,s,t,n); 22 if(t >= mid+1) 23 change(rc,mid+1,y,s,t,n); 24 tree[u] = tree[lc] | tree[rc]; 25 } 26 void query(int u,int x,int y,int s,int t,int &ans) 27 { 28 int mid = (x+y)>>1,lc = u<<1,rc = lc|1; 29 if( (s <= x && y <= t) || single(tree[u]) ) 30 { 31 ans |= tree[u] ; 32 return ; 33 } 34 if(s <= mid) 35 query(lc,x,mid,s,t,ans); 36 if(t >= mid+1) 37 query(rc,mid+1,y,s,t,ans); 38 } 39 int cal(int n) 40 { 41 int m=0; 42 for(int i = 0; i < 30; i++) 43 if( (n>>i) & 1 ) m++; 44 return m; 45 } 46 int main() 47 { 48 int l,n,m,i,a,b,t,ans; 49 char cmd; 50 while(~scanf("%d%d%d",&l,&n,&m)) 51 { 52 tree[1] = 1; 53 for(i = 0; i < m; i++) 54 { 55 getchar(); 56 scanf("%c",&cmd); 57 if(cmd == 'C') 58 { 59 scanf("%d%d%d",&a,&b,&t); 60 if(a > b) a^=b^=a^=b; 61 change(1,1,l,a,b,t); 62 } 63 else 64 { 65 scanf("%d%d",&a,&b); 66 if(a > b) a^=b^=a^=b; 67 ans = 0; 68 query(1,1,l,a,b,ans); 69 printf("%d\n",cal(ans)); 70 } 71 } 72 } 73 return 0; 74 }
本来我是挺得意的,可是che男说,HH大神经常这么做。不带这么打击人的。