BSOJ2869:染色 LCT

来源:互联网 发布:mysql的配置文件在哪里 编辑:程序博客网 时间:2024/05/06 15:19
2869 -- 【SDOI2011】染色
Description
  给定一棵有n个节点的无根树和m个操作,操作有2类:
  1、将节点a到节点b路径上所有点都染成颜色c;
  2、询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由3段组成:“11”、“222”和“1”。
  请你写一个程序依次完成这m个操作。


Input
  第一行包含2个整数n和m,分别表示节点数和操作数;
  第二行包含n个正整数表示n个节点的初始颜色
  下面 行每行包含两个整数x和y,表示x和y之间有一条无向边。
  下面 行每行描述一个操作:
  “C a b c”表示这是一个染色操作,把节点a到节点b路径上所有点(包括a和b)都染成颜色c;
  “Q a b”表示这是一个询问操作,询问节点a到节点b(包括a和b)路径上的颜色段数量。


Output
  对于每个询问操作,输出一行答案。
Sample Input
6 5
2 2 1 2 1 1
1 2
1 3
2 4
2 5
2 6
Q 3 5
C 2 1 1
Q 3 5
C 5 1 2
Q 3 5
Sample Output
3
1
2


多记录color changecolor left(right)color sum几个标记,在上下传时维护,其余做法与标准模板无异。

维护的时候有几个重要的细节!
1.下传
(1).rev旋转时  L,R; lc,rc; L.lc,L.rc; R.lc,R.rc 都要swap。
(2).changecolor时 L,R有关颜色的所有标记都要转换,sum改为1,x.changecol还原为0。
3.上传实质是标记合并,别把lc和rc忘了。 
4.Access()时,x的儿子变化,一定要Pushup(x);
5.sum的初值是1.

TALK IS CHEAP,SHOW ME THE CODE.

#include<iostream>#include<cstdio>#include<cstring>using namespace std;int n,m;struct Splaytree{int l,r,lc,rc,sum,col,fa;int rev,changecol,onp;}tree[200005];void Pushdown(int x){if(tree[x].rev){swap(tree[x].l,tree[x].r);swap(tree[tree[x].l].lc,tree[tree[x].l].rc);   swap(tree[tree[x].r].lc,tree[tree[x].r].rc);   swap(tree[x].lc,tree[x].rc);tree[tree[x].l].rev^=1;tree[tree[x].r].rev^=1;tree[x].rev=0;}if(tree[x].changecol){if(tree[x].l){tree[tree[x].l].col=tree[tree[x].l].lc=tree[tree[x].l].rc=tree[x].changecol;tree[tree[x].l].sum=1;}if(tree[x].r){tree[tree[x].r].col=tree[tree[x].r].lc=tree[tree[x].r].rc=tree[x].changecol;tree[tree[x].r].sum=1;}   tree[tree[x].l].changecol=tree[tree[x].r].changecol=tree[x].changecol;   tree[x].changecol=0;}}void Pushup(int x){tree[x].sum=tree[tree[x].l].sum+tree[tree[x].r].sum+1;tree[x].sum-=((tree[tree[x].r].lc==tree[x].col)+(tree[tree[x].l].rc==tree[x].col));tree[x].lc=tree[x].rc=tree[x].col;if(tree[x].l)tree[x].lc=tree[tree[x].l].lc;if(tree[x].r)tree[x].rc=tree[tree[x].r].rc;}void leftrotate(int x){int y=tree[x].fa;tree[y].r=tree[x].l;if(tree[x].l)tree[tree[x].l].fa=y;tree[x].l=y;tree[x].fa=tree[y].fa;if(tree[y].onp){if(y==tree[tree[y].fa].l)tree[tree[y].fa].l=x;else tree[tree[y].fa].r=x;}tree[y].fa=x;if(tree[y].onp==0){tree[y].onp=1;tree[x].onp=0;}Pushup(y);}void rightrotate(int x){int y=tree[x].fa;tree[y].l=tree[x].r;if(tree[x].r)tree[tree[x].r].fa=y;tree[x].r=y;tree[x].fa=tree[y].fa;if(tree[y].onp){if(y==tree[tree[y].fa].l)tree[tree[y].fa].l=x;else tree[tree[y].fa].r=x;}tree[y].fa=x;if(tree[y].onp==0){tree[y].onp=1;tree[x].onp=0;}Pushup(y);}void Splay(int x){    Pushdown(x);while(tree[x].onp){int y=tree[x].fa,z=tree[y].fa;if(tree[y].onp)Pushdown(z);Pushdown(y);Pushdown(x);if(tree[y].onp==0){if(tree[y].l==x)rightrotate(x);else leftrotate(x);break;}if(x==tree[y].l){if(y==tree[z].l)rightrotate(y),rightrotate(x);else rightrotate(x),leftrotate(x);}else {if(y==tree[z].l)leftrotate(x),rightrotate(x);else leftrotate(y),leftrotate(x);}}Pushup(x);}void Access(int x){int v=0;while(x){Splay(x);tree[tree[x].r].onp=0;tree[v].onp=1;tree[x].r=v;Pushup(x);v=x;x=tree[x].fa;}}void Makeroot(int x){Access(x);Splay(x);    tree[x].rev^=1;}void Link(int v,int w){Makeroot(v);tree[v].fa=w;}void ass_we_can(){int coll,a,b;scanf("%d%d",&n,&m);for(int i=1;i<=n;i++){scanf("%d",&coll);tree[i].lc=tree[i].rc=tree[i].col=coll;tree[i].sum=1;}    for(int i=2;i<=n;i++){scanf("%d%d",&a,&b);Link(a,b);}}void oh_yes_sir(){char cmd;while(m--){int coll,a,b;scanf("%s",&cmd);if(cmd=='C'){scanf("%d%d%d",&a,&b,&coll);Makeroot(a);Access(b);Splay(b);tree[b].lc=tree[b].rc=tree[b].col=tree[b].changecol=coll;tree[b].sum=1;}if(cmd=='Q'){scanf("%d%d",&a,&b);Makeroot(a);Access(b);Splay(b);printf("%d\n",tree[b].sum);}}}int main(){ass_we_can();oh_yes_sir();return 0;}


最后两个函数的名字怪怪的  哲学复兴不可挡

傻傻地写程序时,犯的无下限错误:
 1. 上下传的时候标记都没整完,L.lc,rc和R.lc,rc没交换,详见文首
 2.sum初值设为0,傻傻分不清。
 3. changecol时sum未还原为1
 4. Accss时没有Pushup(x);

0 0
原创粉丝点击