洛谷P2486 [SDOI2011]染色
阿新 • • 發佈:2018-12-31
題目描述
輸入輸出格式
輸入格式:
輸出格式:
對於每個詢問操作,輸出一行答案。
輸入輸出樣例
輸入樣例#1:
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
輸出樣例#1:
3
1
2
說明
思路:對於題目中的操作\(1\),我們可以用樹鏈剖分來實現,就是樹鏈剖分的基本操作,難點就在於操作\(2\),這個操作是要求求任意兩點間的顏色段數量,單純的用線段樹維護區間和肯定是不行的,那麼就考慮去重,去重機制是怎樣的呢?就是我們記錄一個\(lc\)表示一個區間的左端點顏色是什麼,\(rc\)
程式碼:
#include<cstdio> #include<algorithm> #include<cctype> #include<iostream> #define maxn 100007 #define ls rt<<1 #define rs rt<<1|1 using namespace std; int n,m,head[maxn],d[maxn],size[maxn],son[maxn],w[maxn]; int cnt,num,top[maxn],sum[maxn<<2],lazy[maxn<<2]; int lc[maxn<<2],rc[maxn<<2],fa[maxn],id[maxn],a[maxn]; char s; inline int qread() { char c=getchar();int num=0,f=1; for(;!isdigit(c);c=getchar()) if(c=='-') f=-1; for(;isdigit(c);c=getchar()) num=num*10+c-'0'; return num*f; } struct node { int v,nxt; }e[maxn<<1]; inline void ct(int u, int v) { e[++num].v=v; e[num].nxt=head[u]; head[u]=num; } void dfs1(int u, int f) { size[u]=1; for(int i=head[u];i;i=e[i].nxt) { int v=e[i].v; if(v!=f) { d[v]=d[u]+1; fa[v]=u; dfs1(v,u); size[u]+=size[v]; if(size[v]>size[son[u]]) son[u]=v; } } } void dfs2(int u, int t) { id[u]=++cnt; a[cnt]=w[u]; top[u]=t; if(son[u]) dfs2(son[u],t); for(int i=head[u];i;i=e[i].nxt) { int v=e[i].v; if(v!=fa[u]&&v!=son[u]) dfs2(v,v); } } inline void pushup(int rt) { sum[rt]=sum[ls]+sum[rs]-(lc[rs]==rc[ls]); rc[rt]=rc[rs]; lc[rt]=lc[ls]; } void build(int rt, int l, int r) { if(l==r) { sum[rt]=1; lc[rt]=rc[rt]=a[l]; return; } int mid=(l+r)>>1; build(ls,l,mid); build(rs,mid+1,r); pushup(rt); } inline void pushdown(int rt) { if(lazy[rt]) { sum[ls]=sum[rs]=1; lazy[ls]=lazy[rs]=lc[ls]=lc[rs]=rc[ls]=rc[rs]=lazy[rt]; lazy[rt]=0; } } void modify(int rt, int l, int r, int L, int R, int val) { if(L>r||R<l) return; if(L<=l&&r<=R) { sum[rt]=1; lc[rt]=rc[rt]=lazy[rt]=val; return; } pushdown(rt); int mid=(l+r)>>1; if(L<=mid) modify(ls,l,mid,L,R,val); if(R>mid) modify(rs,mid+1,r,L,R,val); pushup(rt); } int csum(int rt, int l, int r, int L, int R) { if(L>r||R<l) return 0; if(L<=l&&r<=R) return sum[rt]; pushdown(rt); int mid=(l+r)>>1; int ans=0,js=0; if(L<=mid) ans+=csum(ls,l,mid,L,R),js++; if(R>mid) ans+=csum(rs,mid+1,r,L,R),js++; if(js==2) ans-=(rc[ls]==lc[rs]); return ans; } int cx(int rt, int l, int r, int L) { if(l==r) return lc[rt]; int mid=(l+r)>>1; pushdown(rt); if(L<=mid) return cx(ls,l,mid,L); else return cx(rs,mid+1,r,L); } void cal(int x, int y, int val) { int fx=top[x],fy=top[y]; while(fx!=fy) { if(d[fx]<d[fy]) swap(x,y),swap(fx,fy); modify(1,1,cnt,id[fx],id[x],val); x=fa[fx],fx=top[x]; } if(id[x]>id[y]) swap(x,y); modify(1,1,cnt,id[x],id[y],val); } int query(int x, int y) { int fx=top[x],fy=top[y],ans=0; int ans1=0,ans2=0; while(fx!=fy) { if(d[fx]<d[fy]) swap(x,y),swap(fx,fy),swap(ans1,ans2); ans+=csum(1,1,cnt,id[fx],id[x]); ans-=(cx(1,1,cnt,id[x])==ans1); ans1=cx(1,1,cnt,id[fx]); x=fa[fx],fx=top[x]; } if(id[x]>id[y]) swap(x,y),swap(ans1,ans2); ans+=csum(1,1,cnt,id[x],id[y]); if(cx(1,1,cnt,id[x])==ans1) --ans; if(cx(1,1,cnt,id[y])==ans2) --ans; return ans; } int main() { n=qread(),m=qread(); for(int i=1;i<=n;++i) w[i]=qread(); for(int i=1,u,v;i<n;++i) { u=qread(),v=qread(); ct(u,v);ct(v,u); } d[1]=1;dfs1(1,0);dfs2(1,1);build(1,1,n); for(int i=1,x,y,c;i<=m;++i) { cin>>s;x=qread(),y=qread(); if(s=='C') { c=qread(); cal(x,y,c); } else printf("%d\n",query(x,y)); } return 0; }