区间颜色段数=左区间颜色段数+右区间颜色段数-(左区间最右边的颜色==右区间最左边的颜色),用线段树来维护。
在树上维护答案,当时为了维护两个端点的颜色,只是费尽心机,最后突然发现暴力查找不超时……整个人都不好了
(话说SDOI真的很喜欢树链剖分和数论啊……每年都有一道,不是R1就是R2)
#include <cstdio> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> using namespace std; const int MAXN=100000+2; struct HASH{ int u; HASH *next; HASH(){} HASH(int _u,HASH *_next):u(_u),next(_next){} }mem[2*MAXN]; struct NODE{ int c,v,d,t,id,mark,f,son; HASH *table; }node[MAXN]; typedef struct ST{ int l,r,c,lc,rc,same; ST *lchild,*rchild; } *TREE; TREE root; int N,M,cnt,mark[MAXN]; char q; void Insert(int u,int v){ node[u].table=&(mem[cnt++]=HASH(v,node[u].table));} void DFS1(int x,int f,int d){ node[x].c=1,node[x].f=f,node[x].d=d; for(HASH *p=node[x].table;p;p=p->next) if(p->u!=f){ DFS1(p->u,x,d+1); node[x].c+=node[p->u].c; if(!node[x].son || node[p->u].c>node[node[x].son].c) node[x].son=p->u; } } void DFS2(int x,int t){ node[x].t=t,node[x].mark=++cnt,mark[cnt]=x; if(!node[x].son) return; DFS2(node[x].son,t); for(HASH *p=node[x].table;p;p=p->next) if(p->u!=node[x].son && p->u!=node[x].f) DFS2(p->u,p->u); } void Pushup(TREE &x){ x->c=x->lchild->c+x->rchild->c; x->lc=x->lchild->lc,x->rc=x->rchild->rc; if(x->lchild->rc==x->rchild->lc) x->c--; } void Pushdown(TREE &x){ if(x->same){ x->lchild->c=x->rchild->c=1; x->lchild->lc=x->lchild->rc=x->same; x->rchild->lc=x->rchild->rc=x->same; x->lchild->same=x->same,x->rchild->same=x->same,x->same=0; } } void Build(TREE &x,int l,int r){ x=new ST; x->l=l,x->r=r,x->same=0,x->lchild=x->rchild=0; if(l==r){ x->c=1,x->lc=x->rc=node[mark[l]].v; return; } int m=(l+r)>>1; Build(x->lchild,l,m),Build(x->rchild,m+1,r); Pushup(x); } void Update(TREE &x,int l,int r,int c){ if(l<=x->l && r>=x->r){ x->c=1,x->lc=x->rc=x->same=c; return; } Pushdown(x); int m=(x->l+x->r)>>1; if(l<=m) Update(x->lchild,l,r,c); if(r>m) Update(x->rchild,l,r,c); Pushup(x); } void Change(int u,int v,int c){ while(node[u].t!=node[v].t){ if(node[node[u].t].d<node[node[v].t].d) swap(u,v); Update(root,node[node[u].t].mark,node[u].mark,c); u=node[node[u].t].f; } if(node[u].d>node[v].d) swap(u,v); Update(root,node[u].mark,node[v].mark,c); } int Query(TREE &x,int l,int r){ if(l<=x->l && r>=x->r) return x->c; Pushdown(x); int m=(x->l+x->r)>>1,ret=0; if(l<=m) ret+=Query(x->lchild,l,r); if(r>m) ret+=Query(x->rchild,l,r); if(l<=m && r>m && x->lchild->rc==x->rchild->lc) ret--; return ret; } int Find(TREE &x,int p){ if(x->l==x->r) return x->lc; Pushdown(x); int m=(x->l+x->r)>>1; if(p<=m) return Find(x->lchild,p); return Find(x->rchild,p); } int Summation(int u,int v){ int ret=0; while(node[u].t!=node[v].t){ if(node[node[u].t].d<node[node[v].t].d) swap(u,v); ret+=Query(root,node[node[u].t].mark,node[u].mark); u=node[u].t; if(Find(root,node[u].mark)==Find(root,node[node[u].f].mark)) ret--; u=node[u].f; } if(node[u].d>node[v].d) swap(u,v); ret+=Query(root,node[u].mark,node[v].mark); return ret; } int main(){ memset(node,0,sizeof(node)); cin >> N >> M; for(int i=1;i<=N;i++) cin >> node[i].v; for(int i=1,u,v;i<N;i++){ cin >> u >> v; Insert(u,v),Insert(v,u); } DFS1(1,0,1); cnt=0,DFS2(1,1); cnt=0,Build(root,1,N); for(int i=1,a,b,c;i<=M;i++){ cin >> q; cin >> a >> b; if(q=='C'){ cin >> c; Change(a,b,c); } if(q=='Q') cout << Summation(a,b) << endl; } return 0; }