【題解】Luogu P4679 [ZJOI2011]道館之戰
阿新 • • 發佈:2019-01-02
原題傳送門
碼農題樹剖好題
這道題要用樹鏈剖分(好像也有神仙用LCT),我部落格裡有對樹鏈剖分的詳細介紹
考慮在鏈上的情況,在當前考慮的區間中,令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; }