P4679 [ZJOI2011] 道馆之战
题意
给一棵 \(n\) 个点的树,每个点有一个两字符的字符串作为权值,其中每个字符为 . 或 #。\(m\) 次操作,单点修改,查询从 \(u\) 走到 \(v\),不能经过 #,每个 . 只能经过一次,最多能经过多少个 .。
\(n\le5\times10^4,m\le10^5\)。
思路
用树剖将树问题转化为序列问题,用线段树维护。每个点存储 \(a_{0/1,0/1}\) 表示当前区间第一步走 \(A/B\) 房间,最后一步走 \(A/B\) 房间的最大点数。\(in_{0/1}\) 表示当前区间从前向后走第一步走 \(A/B\) 房间的最大步数,\(out_{0/1}\) 表示到这走第一步走 \(A/B\) 房间的最大步数。查询链的时候把 \(u\rightarrow v\) 拆分成 \(u\rightarrow lca(u,v)\) 和 \(lca(u,v)\rightarrow v\),要注意一下每条路径的方向。
代码
// Problem: P4679 [ZJOI2011] 道馆之战
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P4679
// Memory Limit: 250 MB
// Time Limit: 1000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include<bits/stdc++.h>
using namespace std;
namespace IO{
template<typename T>
inline void read(T&x){
x=0;char c=getchar();bool f=0;
while(!isdigit(c)) c=='-'?f=1:0,c=getchar();
while(isdigit(c)) x=x*10+c-'0',c=getchar();
f?x=-x:0;
}
template<typename T>
inline void write(T x){
if(x==0){putchar('0');return ;}
x<0?x=-x,putchar('-'):0;short st[50],top=0;
while(x) st[++top]=x%10,x/=10;
while(top) putchar(st[top--]+'0');
}
inline void read(char&c){c=getchar();while(isspace(c)) c=getchar();}
inline void write(char c){putchar(c);}
inline void read(string&s){s.clear();char c;read(c);while(!isspace(c)&&~c) s+=c,c=getchar();}
inline void write(string s){for(int i=0,len=s.size();i<len;i++) putchar(s[i]);}
template<typename T>inline void write(T*x){while(*x) putchar(*(x++));}
template<typename T,typename...T2> inline void read(T&x,T2&...y){read(x),read(y...);}
template<typename T,typename...T2> inline void write(const T x,const T2...y){write(x),putchar(' '),write(y...),sizeof...(y)==1?putchar('\n'):0;}
}using namespace IO;
const int maxn=50010,inf=100000000;
int n,m;
vector<int>e[maxn];
struct node{
int a[2][2],in[2],out[2];
node(){a[0][0]=a[0][1]=a[1][0]=a[1][1]=in[0]=in[1]=out[0]=out[1]=0;}
};
node merge(node a,node b){
node ans;
ans.a[0][0]=max(a.a[0][0]+b.a[0][0],a.a[0][1]+b.a[1][0]);
ans.a[0][1]=max(a.a[0][0]+b.a[0][1],a.a[0][1]+b.a[1][1]);
ans.a[1][0]=max(a.a[1][0]+b.a[0][0],a.a[1][1]+b.a[1][0]);
ans.a[1][1]=max(a.a[1][0]+b.a[0][1],a.a[1][1]+b.a[1][1]);
ans.in[0]=max({a.in[0],a.a[0][0]+b.in[0],a.a[0][1]+b.in[1],-inf});
ans.in[1]=max({a.in[1],a.a[1][0]+b.in[0],a.a[1][1]+b.in[1],-inf});
ans.out[0]=max({b.out[0],a.out[0]+b.a[0][0],a.out[1]+b.a[1][0],-inf});
ans.out[1]=max({b.out[1],a.out[0]+b.a[0][1],a.out[1]+b.a[1][1],-inf});
ans.a[0][0]=max(ans.a[0][0],-inf);
ans.a[0][1]=max(ans.a[0][1],-inf);
ans.a[1][0]=max(ans.a[1][0],-inf);
ans.a[1][1]=max(ans.a[1][1],-inf);
return ans;
}
void swap(node&a){swap(a.a[0][1],a.a[1][0]),swap(a.in[0],a.out[0]),swap(a.in[1],a.out[1]);}
class Segment_Tree{
private:
node t[maxn*4];
void push_up(int u){t[u]=merge(t[u<<1],t[u<<1|1]);}
void update(int u,int l,int r,int d,string z){
if(l>d||r<d) return ;
if(l==r){
t[u].a[0][0]=t[u].a[0][1]=t[u].a[1][0]=t[u].a[1][1]=-inf;
if(z[0]=='.') t[u].a[0][0]=1;
if(z[1]=='.') t[u].a[1][1]=1;
if(z[0]=='.'&&z[1]=='.') t[u].a[0][1]=t[u].a[1][0]=2;
t[u].in[0]=max(t[u].a[0][0],t[u].a[0][1]);
t[u].in[1]=max(t[u].a[1][0],t[u].a[1][1]);
t[u].out[0]=max(t[u].a[0][0],t[u].a[1][0]);
t[u].out[1]=max(t[u].a[0][1],t[u].a[1][1]);
return ;
}
int mid=l+r>>1;
update(u<<1,l,mid,d,z),update(u<<1|1,mid+1,r,d,z);
t[u]=merge(t[u<<1],t[u<<1|1]);
}
node query(int u,int l,int r,int ll,int rr){
if(ll<=l&&r<=rr) return t[u];
if(l>rr||r<ll) return node();
int mid=l+r>>1;
if(rr<=mid) return query(u<<1,l,mid,ll,rr);
if(ll>mid) return query(u<<1|1,mid+1,r,ll,rr);
return merge(query(u<<1,l,mid,ll,rr),query(u<<1|1,mid+1,r,ll,rr));
}
public:
void update(int d,string z){update(1,1,n,d,z);}
node query(int l,int r){return query(1,1,n,l,r);}
}t;
namespace HLD{
int dfn[maxn],cnt_dfn,son[maxn],sz[maxn],fa[maxn],deep[maxn],top[maxn];
void dfs(int u){
sz[u]=1;
deep[u]=deep[fa[u]]+1;
for(int v:e[u]){
if(v==fa[u]) continue;
fa[v]=u;
dfs(v);
sz[u]+=sz[v];
if(sz[v]>sz[son[u]]) son[u]=v;
}
}
void dfs2(int u,int nwtop){
top[u]=nwtop;
dfn[u]=++cnt_dfn;
if(son[u]) dfs2(son[u],nwtop);
for(int v:e[u]) if(v!=fa[u]&&v!=son[u]) dfs2(v,v);
}
void build(){
dfs(1);
dfs2(1,1);
}
void update(int u,string s){t.update(dfn[u],s);}
int query(int u,int v){
node ansu,ansv;
ansu.a[0][0]=ansv.a[0][0]=-1;
while(top[u]!=top[v]){
if(deep[top[u]]<deep[top[v]]){
node nw=t.query(dfn[top[v]],dfn[v]);
if(~ansv.a[0][0]) ansv=merge(nw,ansv);
else ansv=nw;
v=fa[top[v]];
}
else{
node nw=t.query(dfn[top[u]],dfn[u]);
swap(nw);
if(~ansu.a[0][0]) ansu=merge(ansu,nw);
else ansu=nw;
u=fa[top[u]];
}
}
if(deep[u]<deep[v]){
node nw=t.query(dfn[u],dfn[v]);
if(~ansv.a[0][0]) ansv=merge(nw,ansv);
else ansv=nw;
}
else{
node nw=t.query(dfn[v],dfn[u]);
swap(nw);
if(~ansu.a[0][0]) ansu=merge(ansu,nw);
else ansu=nw;
}
node ans;
if(ansu.a[0][0]==-1) ans=ansv;
else if(ansv.a[0][0]==-1) ans=ansu;
else ans=merge(ansu,ansv);
return max({ans.in[0],ans.in[1],0});
}
};
signed main(){
read(n,m);
for(int i=1;i<n;i++){
int u,v;read(u,v);
e[u].push_back(v),e[v].push_back(u);
}
HLD::build();
for(int i=1;i<=n;i++){
string s;read(s);
HLD::update(i,s);
}
for(int i=1;i<=m;i++){
char op;int u,v;string s;
read(op,u);
if(op=='C') read(s),HLD::update(u,s);
else read(v),write(HLD::query(u,v)),write("\n");
}
return 0;
}

浙公网安备 33010602011771号