今天训练的内容是线段树。
线段树的基本结构,空间大小,常用操作的复杂度已不必多说。主要针对训练中出线的一些问题做一些小的总结
总得来说,对于线段树的编码和调试能力还比较欠缺,这一点希望通过多次的训练来解决
对于各种线段树模型,应用方法则需要经验的积累
ZJU 1610:
线段树的入门题,主要注意的是线段树处理过程中一般如果能覆盖当前区间,操作一般都会终止。这种情况下,如果题意中该区间的操作会影响子区间,那么需要通过一些步骤调整。典型的就是染色。对一个染成同一中颜色的区间的一个子区间染色,我们首先先要将该区间的颜色传递到它的子区间上。见代码line39
- #include <iostream>
- using namespace std;
- const int N = 8010;
- struct node
- {
- int x, y;
- int color;
- }seg[3*N];
- int cnt[N];
- int num[N];
- void build(int root, int x, int y)
- {
- seg[root] = (node){x, y, -1};
- if(y > x + 1)
- {
- int mid = (x + y) >> 1;
- build(root * 2, x, mid);
- build(root * 2 + 1, mid, y);
- }
- }
- void insert(int root, int x, int y, int c)
- {
- if(x <= seg[root].x && y >= seg[root].y)
- {
- int j = seg[root].color;
- seg[root].color = c;
- }
- else
- {
- int mid = (seg[root].x + seg[root].y) >> 1;
- if(seg[root].color >= 0)
- {
- seg[root*2].color = seg[root*2 + 1].color = seg[root].color;
- seg[root].color = -1;
- }
- if(x < mid) insert(root * 2, x, y, c);
- if(y > mid) insert(root * 2 + 1, x, y, c);
- }
- }
- void query(int x)
- {
- int i, j;
- if(seg[x].color >= 0)
- for(int i = seg[x].x + 1; i <= seg[x].y; i++) cnt[i] = seg[x].color;
- else if(seg[x].x + 1 == seg[x].y) cnt[seg[x].y] = -1;
- else
- {
- query(2*x);
- query(2*x+1);
- }
- }
- int main()
- {
- int i, j, k, m;
- while(scanf("%d",&m) == 1)
- {
- memset(cnt, 0, sizeof(cnt));
- memset(num, 0, sizeof(num));
- build(1, 0, 8000);
- for(; m; m--)
- {
- scanf("%d%d%d",&i, &j, &k);
- insert(1, i, j, k);
- }
- query(1);
- i = 1;
- while(i <= 8000)
- {
- while(i <= 8000 && cnt[i]==-1) i++;
- if(i > 8000) break;
- j = i + 1;
- while(j <= 8000 && cnt[j]==cnt[i]) j++;
- num[cnt[i]]++;
- i = j;
- }
- for(i = 0; i <= 8000; i++)
- if(num[i] != 0) printf("%d %d/n",i, num[i]);
- printf("/n");
- }
- return 0;
- }
PKU 2777:
和上题相似。注意的地方在于。查询的时候,递归结束既可能是因为覆盖了整个区间,也可能是整个区间只有一中颜色。
line 54
- #include <iostream>
- const int N = 100010;
- struct node
- {
- int x, y;
- int color;
- bool oneColor;
- }seg[N<<2];
- int T;
- void build(int root, int x, int y)
- {
- seg[root] = (node){x, y, 1, true};
- if(x != y)
- {
- int mid = (x + y) >> 1;
- build(root * 2, x, mid);
- build(root * 2 + 1, mid + 1, y);
- }
- }
- void insert(int root, int x, int y, int c)
- {
- if(x <= seg[root].x && y >= seg[root].y){
- seg[root].color = (1<<c);
- seg[root].oneColor = true;
- }
- else
- {
- if(seg[root].oneColor) {
- seg[root*2].color = seg[root*2+1].color = seg[root].color;
- seg[root*2].oneColor = seg[root*2+1].oneColor = true;
- if((1<<c) != seg[root].color) seg[root].oneColor = false;
- }
- int mid = (seg[root].x + seg[root].y) >> 1;
- if(x <= mid)
- insert(root*2, x, y, c);
- if(y > mid)
- insert(root*2 + 1, x, y, c);
- seg[root].color = seg[root*2].color | seg[root*2+1].color;
- }
- }
- int query(int root, int x, int y)
- {
- if(x <= seg[root].x && y >= seg[root].y)
- return seg[root].color;
- if(seg[root].oneColor) return seg[root].color;
- else
- {
- int mid = (seg[root].x + seg[root].y) >> 1;
- int ans = 0;
- if(x <= mid) ans |= query(root*2, x, y);
- if(y > mid) ans |= query(root*2 + 1, x, y);
- return ans;
- }
- }
- inline int getNum(int x)
- {
- int i = 0;
- while(x != 0) { i += x%2; x/=2;}
- return i;
- }
- int main()
- {
- int n, m;
- int i, j, k;
- scanf("%d%d%d",&n, &T, &m);
- build(1, 1, n);
- for(; m; m--)
- {
- getchar();
- char ch = getchar();
- if(ch == 'C')
- {
- scanf("%d%d%d",&i, &j, &k);
- if(i > j) { int t = i; i = j; j = t;}
- insert(1, i, j, k-1);
- }
- else
- {
- scanf("%d%d",&i, &j);
- if(i > j) { int t = i; i = j; j = t;}
- printf("%d/n",getNum(query(1, i, j)));
- }
- }
- return 0;
- }