一、题目
二、解法
这道题卡了一会,看过网上的题解,都没懂,讲一下我自己 y y yy yy的一种解法。
首先维护每个点的最左颜色 l c lc lc,最右颜色 r c rc rc,总颜色段数,和颜色覆盖标记,合并 A , B A,B A,B时就判断 A . r c = B . l c A.rc=B.lc A.rc=B.lc是否成立,成立就把总颜色段数减一。这个合并可以重载加法,懒标记的处理也不难,线段树基本操作就可以维护剖分树链。
最有意思的地方还是询问,要把询问颜色段数放在树上,那么详细讲一下:
我们先拼凑
u
u
u到相同
t
o
p
top
top的路径,由于询问返回的段是深度小-深度大
,我们需要把询问返回的段给翻转(具体就是直接交换左右颜色),设
t
t
t是原来的,
t
′
t'
t′是新的段,就用
t
+
t
′
t+t'
t+t′来拼接。对于
v
v
v,不需要翻转,直接用
t
′
+
t
t'+t
t′+t来拼接即可。
跑到一个 t o p top top后我们要考虑 u , v u,v u,v的相对位置,如果 u u u在上面(深度小),直接接到中间。如果 v v v在上面,翻转后拼接到中间即可。
#pragma GCC optimize(2)
#include <cstdio>
#include <cstring>
#include <iostream>
#define inf 0x3f3f3f3f
using namespace std;
const int M = 100005;
int read()
{
int x=0,flag=1;char c;
while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*flag;
}//区间修改,颜色段数
int n,m,tot,a[M],c[M],siz[M],f[M],fa[M];
int Index,son[M],dep[M],num[M],top[M];
char s[5];
struct edge
{
int v,next;
edge(int V=0,int N=0) : v(V) , next(N) {}
}e[2*M];
struct node
{
int lc,rc,sum,la;
node(int L=0,int R=0,int S=0,int La=0) : lc(L) , rc(R) , sum(S) , la(La) {}
node operator + (const node &B) const {
if(sum==0) return B;
if(B.sum==0) return *this;
return node(lc,B.rc,sum+B.sum-(rc==B.lc),0);
}
void reverse() {
swap(lc,rc);
}
}tr[4*M];
void dfs1(int u,int p)
{
fa[u]=p;
dep[u]=dep[p]+1;
siz[u]=1;
for(int i=f[u];i;i=e[i].next)
{
int v=e[i].v;
if(v==p) continue;
dfs1(v,u);
siz[u]+=siz[v];
if(siz[v]>siz[son[u]])
son[u]=v;
}
}
void dfs2(int u,int tp)
{
top[u]=tp;
num[u]=++Index;
c[Index]=a[u];
if(son[u]) dfs2(son[u],tp);
for(int i=f[u];i;i=e[i].next)
if(e[i].v^son[u] && e[i].v^fa[u])
dfs2(e[i].v,e[i].v);
}
void build(int i,int l,int r)
{
if(l==r)
{
tr[i]=node(c[l],c[l],1,0);
return ;
}
int mid=(l+r)>>1;
build(i<<1,l,mid);
build(i<<1|1,mid+1,r);
tr[i]=tr[i<<1]+tr[i<<1|1];
}
void change(int i,int c)
{
tr[i]=node(c,c,1,c);
}
void down(int i)
{
if(tr[i].la==0) return ;
change(i<<1,tr[i].la);
change(i<<1|1,tr[i].la);
tr[i].la=0;
}
void updata(int i,int l,int r,int L,int R,int v)
{
if(l>R || L>r) return ;
if(L<=l && r<=R)
{
change(i,v);
return ;
}
down(i);
int mid=(l+r)>>1;
updata(i<<1,l,mid,L,R,v);
updata(i<<1|1,mid+1,r,L,R,v);
tr[i]=tr[i<<1]+tr[i<<1|1];
}
node query(int i,int l,int r,int L,int R)
{
if(l>R || L>r) return 0;
if(L<=l && r<=R) return tr[i];
down(i);
int mid=(l+r)>>1;
node t1=query(i<<1,l,mid,L,R);
return t1+query(i<<1|1,mid+1,r,L,R);
}
void modify(int u,int v,int c)
{
while(top[u]^top[v])
{
if(dep[top[u]]<=dep[top[v]]) swap(u,v);
updata(1,1,n,num[top[u]],num[u],c);
u=fa[top[u]];
}
if(dep[u]<=dep[v]) swap(u,v);
updata(1,1,n,num[v],num[u],c);
}
int ask(int u,int v)
{
node t1,t2;
while(top[u]^top[v])
{
if(dep[top[u]]>=dep[top[v]])
{
node t=query(1,1,n,num[top[u]],num[u]);
t.reverse();
t1=t1+t;
u=fa[top[u]];
}
else
{
t2=query(1,1,n,num[top[v]],num[v])+t2;
v=fa[top[v]];
}
}
if(dep[u]>=dep[v])
{
node t=query(1,1,n,num[v],num[u]);
t.reverse();
t1=t1+t+t2;
return t1.sum;
}
t1=t1+query(1,1,n,num[u],num[v])+t2;
return t1.sum;
}
int main()
{
n=read();m=read();
for(int i=1;i<=n;i++)
a[i]=read();
for(int i=1;i<n;i++)
{
int u=read(),v=read();
e[++tot]=edge(v,f[u]),f[u]=tot;
e[++tot]=edge(u,f[v]),f[v]=tot;
}
dfs1(1,0);
dfs2(1,1);
build(1,1,n);
while(m--)
{
scanf("%s",s);
int u=read(),v=read();
if(s[0]=='C')
modify(u,v,read());
else
printf("%d\n",ask(u,v));
}
}