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 5Sample Output
3
1 2HINT
数N<=10^5,操作数M<=10^5,所有的颜色C为整数且在[0, 10^9]之间。
Solution
这题有很多做法,树剖,LCT
因为现在正在练LCT,所以就用LCT写了 一条链上,维护四个东西,col(结点本身颜色),lco(结点包括其Splay子树代表的一段颜色的最左边颜色),rco(这个就是最右边的),sum(结点包括其Splay子树代表的一段的答案) 因为LCT的Splay保证了中序遍历按深度递增,所以一个结点包括其子树后包含的位置一定是连续的一段,所以可以这样维护 然后对于pushup 首先直接把两个儿子的sum与自己的长度1全部加上后 再判断连接的地方是否相同,如果相同就减去多加的(这个地方可能说不清楚,但一看代码就明白了) 然后当前结点的lco就是左儿子的lco,rco就是右儿子的rco 还要注意如果没有左右儿子,就千万不要转移,否则会出问题,lco和rco会转移错误#include#define ll long long#define db double#define ld long doubleconst int MAXN=100000+10;int n,m;#define lc(x) ch[(x)][0]#define rc(x) ch[(x)][1]struct LCT{ int ch[MAXN][2],fa[MAXN],rev[MAXN],sum[MAXN],lco[MAXN],rco[MAXN],pnt[MAXN],stack[MAXN],cnt,col[MAXN]; inline bool nroot(int x) { return lc(fa[x])==x||rc(fa[x])==x; } inline void reverse(int x) { std::swap(lc(x),rc(x)); std::swap(lco[x],rco[x]); rev[x]^=1; } inline void paint(int x,int c) { sum[x]=1; pnt[x]=col[x]=lco[x]=rco[x]=c; } inline void pushup(int x) { sum[x]=sum[lc(x)]+sum[rc(x)]+1; if(lc(x)&&rc(x))sum[x]=sum[x]-(rco[lc(x)]==col[x])-(col[x]==lco[rc(x)]); else if(lc(x))sum[x]=sum[x]-(rco[lc(x)]==col[x]); else if(rc(x))sum[x]=sum[x]-(col[x]==lco[rc(x)]); lco[x]=rco[x]=col[x]; if(lc(x))lco[x]=lco[lc(x)]; if(rc(x))rco[x]=rco[rc(x)]; } inline void pushdown(int x) { if(pnt[x]) { if(lc(x))paint(lc(x),pnt[x]); if(rc(x))paint(rc(x),pnt[x]); pnt[x]=0; } if(rev[x]) { if(lc(x))reverse(lc(x)); if(rc(x))reverse(rc(x)); rev[x]=0; } } inline void rotate(int x) { int f=fa[x],p=fa[f],c=(rc(f)==x); if(nroot(f))ch[p][rc(p)==f]=x; fa[ch[f][c]=ch[x][c^1]]=f; fa[ch[x][c^1]=f]=x; fa[x]=p; pushup(f); pushup(x); } inline void splay(int x) { cnt=0; stack[++cnt]=x; for(register int i=x;nroot(i);i=fa[i])stack[++cnt]=fa[i]; while(cnt)pushdown(stack[cnt--]); for(register int y=fa[x];nroot(x);rotate(x),y=fa[x]) if(nroot(y))rotate((lc(y)==x)==(lc(fa[y])==y)?y:x); pushup(x); } inline void access(int x) { for(register int y=0;x;x=fa[y=x])splay(x),rc(x)=y,pushup(x); } inline void makeroot(int x) { access(x);splay(x);reverse(x); } inline void split(int x,int y) { makeroot(x);access(y);splay(y); } inline void link(int x,int y) { makeroot(x);fa[x]=y; }};LCT T;#undef lc#undef rcinline void read(int &x){ int data=0,w=1; char ch=0; while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar(); if(ch=='-')w=-1,ch=getchar(); while(ch>='0'&&ch<='9')data=(data<<3)+(data<<1)+(ch^'0'),ch=getchar(); x=data*w;}inline void write(int x,char c='\0'){ if(x<0)putchar('-'),x=-x; if(x>9)write(x/10); putchar(x%10+'0'); if(c!='\0')putchar(c);}template inline void chkmin(T &x,T y){x=(y inline void chkmax(T &x,T y){x=(y>x?y:x);}template inline T min(T x,T y){return x inline T max(T x,T y){return x>y?x:y;}int main(){ read(n);read(m); for(register int i=1;i<=n;++i) { int color; read(color); T.col[i]=T.lco[i]=T.rco[i]=color; T.sum[i]=1; } for(register int i=1;i