【题解】Luogu P4679 [ZJOI2011]道馆之战

时间:2023-03-10 07:21:47
【题解】Luogu P4679 [ZJOI2011]道馆之战

原题传送门

码农题树剖好题,口袋妖怪是个好玩的游戏

这道题要用树链剖分,我博客里有对树链剖分的详细介绍

下文左右就代表树的节点按dfs序后的左右,上、下分别表示每个节点的A、B区域

考虑在链上的情况,在当前考虑的区间中,令dis[0][0]表示从左上走到右上的最长路,dis[0][1]表示从左上到右下,dis[1][0],dis[1][1]以此类推. 令maxx[0][0]表示从左上出发能走的最大距离,maxx[0][1]表示左下的,maxx[1][0]表示右上,maxx[1][1]表示右下.它们的合并比较简单.令当前区间为c,左半区间为a,右半区间为b,那么:

	c.dis[0][0]=Max(-inf,Max(a.dis[0][0]+b.dis[0][0],a.dis[0][1]+b.dis[1][0]));
c.dis[0][1]=Max(-inf,Max(a.dis[0][0]+b.dis[0][1],a.dis[0][1]+b.dis[1][1]));
c.dis[1][0]=Max(-inf,Max(a.dis[1][1]+b.dis[1][0],a.dis[1][0]+b.dis[0][0]));
c.dis[1][1]=Max(-inf,Max(a.dis[1][1]+b.dis[1][1],a.dis[1][0]+b.dis[0][1]));
c.maxx[0][0]=Max(a.maxx[0][0],Max(a.dis[0][0]+b.maxx[0][0],a.dis[0][1]+b.maxx[0][1]));
c.maxx[0][1]=Max(a.maxx[0][1],Max(a.dis[1][0]+b.maxx[0][0],a.dis[1][1]+b.maxx[0][1]));
c.maxx[1][0]=Max(b.maxx[1][0],Max(b.dis[0][0]+a.maxx[1][0],b.dis[1][0]+a.maxx[1][1]));
c.maxx[1][1]=Max(b.maxx[1][1],Max(b.dis[0][1]+a.maxx[1][0],b.dis[1][1]+a.maxx[1][1]));

在树上怎么办呢?每次询问的是两个点之间的路径,很显然,要用线段树+树链剖分. 如果询问的两个点分别是x,y,令lans表示x向上跳得到的答案,rans表示y向上跳得到的答案,最后要将lans取反再与rans合并,因为当两个点最后跳到一起时,它们的左端点对应左端点,右端点对应右端点,而我们要求左端点对应右端点,右端点对应左端点,所以要取反(这个珂以画个图理解一下子)

#include <bits/stdc++.h>
#define N 50005
#define inf (1<<30)
using namespace std;
inline int read()
{
register int x=0,f=1;register char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return x*f;
}
inline void write(register int x)
{
if(!x)putchar('0');if(x<0)x=-x,putchar('-');
static int sta[20];register int tot=0;
while(x)sta[tot++]=x%10,x/=10;
while(tot)putchar(sta[--tot]+48);
}
inline void Swap(register int &a,register int &b)
{
a^=b^=a^=b;
}
inline int Max(register int x,register int y)
{
return x>y?x:y;
}
struct edge{
int to,next;
}eg[N<<1];
int head[N],cnt=0;
inline void add(register int u,register int v)
{
eg[++cnt]=(edge){v,head[u]};
head[u]=cnt;
}
int n,m;
int size[N],dep[N],fa[N],son[N];
int tot=0,dl[N],id[N],top[N];
int a[N][2];
inline void dfs1(register int x,register int faa)
{
fa[x]=faa;
size[x]=1;
dep[x]=dep[faa]+1;
for(register int i=head[x];i;i=eg[i].next)
{
int v=eg[i].to;
if(v==faa)
continue;
dfs1(v,x);
size[x]+=size[v];
if(size[v]>size[son[x]])
son[x]=v;
}
}
inline void dfs2(register int x,register int t)
{
dl[x]=++tot;
id[tot]=x;
top[x]=t;
if(son[x])
dfs2(son[x],t);
for(register int i=head[x];i;i=eg[i].next)
{
int v=eg[i].to;
if(v==fa[x]||v==son[x])
continue;
dfs2(v,v);
}
}
struct node{
int dis[2][2],maxx[2][2];
inline void clear()
{
memset(dis,0,sizeof(dis));
memset(maxx,0,sizeof(maxx));
}
inline bool emptyy()
{
if(!dis[0][0]&&!dis[0][1]&&!dis[1][0]&&!dis[1][1]&&!maxx[0][0]&&!maxx[0][1]&&!maxx[1][0]&&!maxx[1][1])
return true;
return false;
}
}e[N<<2];
inline node pushup(register node a,register node b)
{
node c;
if(a.emptyy())
c=b;
else if(b.emptyy())
c=a;
else
{
c.dis[0][0]=Max(-inf,Max(a.dis[0][0]+b.dis[0][0],a.dis[0][1]+b.dis[1][0]));
c.dis[0][1]=Max(-inf,Max(a.dis[0][0]+b.dis[0][1],a.dis[0][1]+b.dis[1][1]));
c.dis[1][0]=Max(-inf,Max(a.dis[1][1]+b.dis[1][0],a.dis[1][0]+b.dis[0][0]));
c.dis[1][1]=Max(-inf,Max(a.dis[1][1]+b.dis[1][1],a.dis[1][0]+b.dis[0][1]));
c.maxx[0][0]=Max(a.maxx[0][0],Max(a.dis[0][0]+b.maxx[0][0],a.dis[0][1]+b.maxx[0][1]));
c.maxx[0][1]=Max(a.maxx[0][1],Max(a.dis[1][0]+b.maxx[0][0],a.dis[1][1]+b.maxx[0][1]));
c.maxx[1][0]=Max(b.maxx[1][0],Max(b.dis[0][0]+a.maxx[1][0],b.dis[1][0]+a.maxx[1][1]));
c.maxx[1][1]=Max(b.maxx[1][1],Max(b.dis[0][1]+a.maxx[1][0],b.dis[1][1]+a.maxx[1][1]));
}
return c;
}
inline void build(register int x,register int l,register int r)
{
if(l==r)
{
int p=a[id[l]][0],q=a[id[l]][1];
if(p==1&&q==1)
{
e[x].dis[0][0]=e[x].dis[1][1]=1;
e[x].dis[0][1]=e[x].dis[1][0]=2;
e[x].maxx[0][0]=e[x].maxx[0][1]=e[x].maxx[1][0]=e[x].maxx[1][1]=2;
}
else if(p==1)
{
e[x].dis[0][0]=1;
e[x].dis[0][1]=e[x].dis[1][0]=e[x].dis[1][1]=-inf;
e[x].maxx[0][0]=e[x].maxx[1][0]=1;
e[x].maxx[0][1]=e[x].maxx[1][1]=-inf;
}
else if(q==1)
{
e[x].dis[0][0]=e[x].dis[0][1]=e[x].dis[1][0]=-inf;
e[x].dis[1][1]=1;
e[x].maxx[0][0]=e[x].maxx[1][0]=-inf;
e[x].maxx[0][1]=e[x].maxx[1][1]=1;
}
else
{
for(register int i=0;i<=1;++i)
for(register int j=0;j<=1;++j)
e[x].dis[i][j]=e[x].maxx[i][j]=-inf;
}
return;
}
int mid=l+r>>1;
build(x<<1,l,mid);
build(x<<1|1,mid+1,r);
e[x]=pushup(e[x<<1],e[x<<1|1]);
}
inline void update(register int x,register int l,register int r,register int v,register int p,register int q)
{
if(l==r)
{
if(p==1&&q==1)
{
e[x].dis[0][0]=e[x].dis[1][1]=1;
e[x].dis[0][1]=e[x].dis[1][0]=2;
e[x].maxx[0][0]=e[x].maxx[0][1]=e[x].maxx[1][0]=e[x].maxx[1][1]=2;
}
else if(p==1)
{
e[x].dis[0][0]=1;
e[x].dis[0][1]=e[x].dis[1][0]=e[x].dis[1][1]=-inf;
e[x].maxx[0][0]=e[x].maxx[1][0]=1;
e[x].maxx[0][1]=e[x].maxx[1][1]=-inf;
}
else if(q==1)
{
e[x].dis[0][0]=e[x].dis[0][1]=e[x].dis[1][0]=-inf;
e[x].dis[1][1]=1;
e[x].maxx[0][0]=e[x].maxx[1][0]=-inf;
e[x].maxx[0][1]=e[x].maxx[1][1]=1;
}
else
{
for(register int i=0;i<=1;++i)
for(register int j=0;j<=1;++j)
e[x].dis[i][j]=e[x].maxx[i][j]=-inf;
}
return;
}
int mid=l+r>>1;
if(v<=mid)
update(x<<1,l,mid,v,p,q);
else
update(x<<1|1,mid+1,r,v,p,q);
e[x]=pushup(e[x<<1],e[x<<1|1]);
}
inline node rev(register node a)
{
Swap(a.maxx[0][0],a.maxx[1][0]);
Swap(a.maxx[0][1],a.maxx[1][1]);
Swap(a.dis[0][1],a.dis[1][0]);
return a;
}
inline node query(register int x,register int l,register int r,register int L,register int R)
{
if(l==L&&r==R)
return e[x];
int mid=l+r>>1;
if(R<=mid)
return query(x<<1,l,mid,L,R);
else if(L>mid)
return query(x<<1|1,mid+1,r,L,R);
else
return pushup(query(x<<1,l,mid,L,mid),query(x<<1|1,mid+1,r,mid+1,R));
}
inline int Query(register int x,register int y)
{
node lans,rans;
lans.clear();
rans.clear();
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]])
{
rans=pushup(query(1,1,n,dl[top[y]],dl[y]),rans);
y=fa[top[y]];
}
else
{
lans=pushup(query(1,1,n,dl[top[x]],dl[x]),lans);
x=fa[top[x]];
}
}
if(dep[x]>dep[y])
lans=pushup(query(1,1,n,dl[y],dl[x]),lans);
else
rans=pushup(query(1,1,n,dl[x],dl[y]),rans);
lans=pushup(rev(lans),rans);
int res=Max(lans.maxx[0][0],lans.maxx[0][1]);
return res<0?0:res;
}
int main()
{
n=read(),m=read();
for(register int i=1;i<n;++i)
{
int u=read(),v=read();
add(u,v),add(v,u);
}
dfs1(1,0);
dfs2(1,1);
for(register int i=1;i<=n;++i)
{
char ch[3];
scanf("%s",ch);
a[i][0]=(ch[0]=='.')?1:0;
a[i][1]=(ch[1]=='.')?1:0;
}
build(1,1,n);
while(m--)
{
char c=getchar();
while(c!='C'&&c!='Q')
c=getchar();
if(c=='C')
{
int u=read();
char s[3];
scanf("%s",s);
int p=(s[0]=='.')?1:0,q=(s[1]=='.')?1:0;
update(1,1,n,dl[u],p,q);
}
else
{
int u=read(),v=read();
write(Query(u,v)),puts("");
}
}
return 0;
}