题目链接:P1505 [国家集训队]旅游
对于边的剖分,将每条边的编号赋值为其后向点的dfs序编号,因为在dfs过程中,儿子节点有且只有一个直接父亲,那么可以将这条边的编号写作这个儿子的编号。
修改一条链上的边权,与点权不同的是,当两个点处于同一条重链的时候,深度较浅的那个点对应的边不属于我们修改的范围:
void updatachain(int x,int y){
while(topp[x]!=topp[y]){
if(dep[topp[x]]<dep[topp[y]]) swap(x,y);
updata(1,n,1,dfn[topp[x]],dfn[x]);
//cout<<dfn[topp[x]]<<" "<<dfn[x]<<endl;
x=fa[topp[x]];
}
if(dep[x]>dep[y]) swap(x,y);
//cout<<dfn[x]+1<<" "<<dfn[y]<<endl;
updata(1,n,1,dfn[x]+1,dfn[y]);
}
预处理比点剖多了一个儿子节点的直连边的边权,其余都一致。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+7;
int maxx[maxn<<2|1],minn[maxn<<2|1],sum[maxn<<2|1],lazy[maxn<<2|1];
struct Edge{
int v,w,next;
}edge[maxn<<1];
int top,head[maxn];
void init(){
top=0;
memset(head,-1,sizeof(head));
}
void add(int u,int v,int w){
edge[top].v=v;
edge[top].w=w;
edge[top].next=head[u];
head[u]=top++;
}
//深度,dfs编号对应的边权,dfs序,编号,重链最顶端,子树大小,重儿子,直接父亲,儿子与父亲的直连边权;
int dep[maxn],val[maxn],dfn[maxn],num,topp[maxn],size1[maxn],son[maxn],fa[maxn],faedge[maxn];
bool vis[maxn];
void dfs1(int u){
size1[u]=1;
vis[u]=1;
int v;
int maxx=-1;
for(int i=head[u];i!=-1;i=edge[i].next){
v=edge[i].v;
if(vis[v]) continue;
dep[v]=dep[u]+1;
fa[v]=u;
faedge[v]=edge[i].w;
dfs1(v);
size1[u]+=size1[v];
if(size1[v]>maxx){
son[u]=v;
maxx=size1[v];
}
}
}
void dfs2(int u,int t,int lastw){
topp[u]=t;
dfn[u]=++num;
val[num]=lastw;
if(!son[u]) return ;
dfs2(son[u],t,faedge[son[u]]);
int v,w;
for(int i=head[u];i!=-1;i=edge[i].next){
v=edge[i].v;
w=edge[i].w;
if(dfn[v]||v==son[u]) continue;
dfs2(v,v,w);
}
}
void pushup(int k){
sum[k]=sum[k<<1]+sum[k<<1|1];
maxx[k]=max(maxx[k<<1],maxx[k<<1|1]);
minn[k]=min(minn[k<<1],minn[k<<1|1]);
}
void pushdown(int k){
int x;
if(lazy[k]){
lazy[k<<1]^=1;
lazy[k<<1|1]^=1;
sum[k<<1]*=-1;
sum[k<<1|1]*=-1;
swap(maxx[k<<1],minn[k<<1]);
maxx[k<<1]*=-1,minn[k<<1]*=-1;
swap(maxx[k<<1|1],minn[k<<1|1]);
maxx[k<<1|1]*=-1,minn[k<<1|1]*=-1;
lazy[k]=0;
}
}
void build(int l,int r,int k){
lazy[k]=0;
if(l==r){
sum[k]=val[l];
maxx[k]=val[l];
minn[k]=val[l];
return ;
}
int mid=(l+r)>>1;
build(l,mid,k<<1);
build(mid+1,r,k<<1|1);
pushup(k);
}
void updata_id(int l,int r,int k,int id,int val){
if(l==r){
sum[k]=minn[k]=maxx[k]=val;
return ;
}
pushdown(k);
int mid=(l+r)>>1;
if(id<=mid) updata_id(l,mid,k<<1,id,val);
else updata_id(mid+1,r,k<<1|1,id,val);
pushup(k);
}
int n;
void updata(int l,int r,int k,int L,int R){
if(L>R) return ;
if(l>R||r<L) return ;
if(l>=L&&r<=R){
lazy[k]^=1;
sum[k]*=-1;
swap(maxx[k],minn[k]);
maxx[k]*=-1,minn[k]*=-1;
return ;
}
int mid=(l+r)>>1;
pushdown(k);
if(L<=mid) updata(l,mid,k<<1,L,R);
if(R>mid) updata(mid+1,r,k<<1|1,L,R);
pushup(k);
}
int myfindsum(int l,int r,int k,int L,int R){
//if(L>R) return 0;
if(l>R||r<L) return 0;
if(l>=L&&r<=R) return sum[k];
int mid=(l+r)>>1;
pushdown(k);
int res=0;
if(L<=mid) res+=myfindsum(l,mid,k<<1,L,R);
if(R>mid) res+=myfindsum(mid+1,r,k<<1|1,L,R);
pushup(k);
return res;
}
const int inf=0x3f3f3f3f;
int myfindmax(int l,int r,int k,int L,int R){
//if(L>R) return -inf;
if(l>R||r<L) return -inf;
if(l>=L&&r<=R) return maxx[k];
int mid=(l+r)>>1;
pushdown(k);
int res=-inf;
if(L<=mid) res=max(res,myfindmax(l,mid,k<<1,L,R));
if(R>mid) res=max(res,myfindmax(mid+1,r,k<<1|1,L,R));
pushup(k);
return res;
}
int myfindmin(int l,int r,int k,int L,int R){
//if(L>R) return inf;
if(l>R||r<L) return inf;
if(l>=L&&r<=R) return minn[k];
int mid=(l+r)>>1;
pushdown(k);
int res=inf;
if(L<=mid) res=min(res,myfindmin(l,mid,k<<1,L,R));
if(R>mid) res=min(res,myfindmin(mid+1,r,k<<1|1,L,R));
pushup(k);
return res;
}
//1 sum,2 max,3 min;
int myfindchain(int x,int y,int id){
int res=0;
if(id==2) res=-inf;
else if(id==3) res=inf;
while(topp[x]!=topp[y]){
if(dep[topp[x]]<dep[topp[y]]) swap(x,y);
if(id==1) res+=myfindsum(1,n,1,dfn[topp[x]],dfn[x]);
else if(id==2) res=max(res,myfindmax(1,n,1,dfn[topp[x]],dfn[x]));
else res=min(res,myfindmin(1,n,1,dfn[topp[x]],dfn[x]));
//cout<<dfn[topp[x]]<<" "<<dfn[x]<<endl;
x=fa[topp[x]];
}
if(dep[x]>dep[y]) swap(x,y);
if(id==1) res+=myfindsum(1,n,1,dfn[x]+1,dfn[y]);
else if(id==2) res=max(res,myfindmax(1,n,1,dfn[x]+1,dfn[y]));
else res=min(res,myfindmin(1,n,1,dfn[x]+1,dfn[y]));
//cout<<dfn[x]+1<<" "<<dfn[y]<<endl;
return res;
}
void updatachain(int x,int y){
while(topp[x]!=topp[y]){
if(dep[topp[x]]<dep[topp[y]]) swap(x,y);
updata(1,n,1,dfn[topp[x]],dfn[x]);
//cout<<dfn[topp[x]]<<" "<<dfn[x]<<endl;
x=fa[topp[x]];
}
if(dep[x]>dep[y]) swap(x,y);
//cout<<dfn[x]+1<<" "<<dfn[y]<<endl;
updata(1,n,1,dfn[x]+1,dfn[y]);
}
char s[9];
int main(){
init();
//freopen("in.txt","r",stdin);
//freopen("out1.txt","w",stdout);
scanf("%d",&n);
int u,v,w;
for(int i=1;i<n;++i){
scanf("%d%d%d",&u,&v,&w);
++u,++v;
add(u,v,w);
add(v,u,w);
}
dep[1]=1;
dfs1(1);
dfs2(1,1,0);
build(1,n,1);
int q;
scanf("%d",&q);
while(q--){
scanf("%s%d%d",s,&u,&v);
if(s[0]=='C'){
--u;
int point=(dep[edge[u<<1].v]>dep[edge[u<<1|1].v]?edge[u<<1].v:edge[u<<1|1].v);
updata_id(1,n,1,dfn[point],v);
}
else if(s[0]=='N') updatachain(u+1,v+1);
else if(s[0]=='S') printf("%d\n",myfindchain(u+1,v+1,1));
else if(s[1]=='A') printf("%d\n",myfindchain(u+1,v+1,2));
else printf("%d\n",myfindchain(u+1,v+1,3));
}
return 0;
}

该博客详细介绍了P1505旅游问题,利用树链剖分的方法解决。内容涉及如何为边编号,以及在dfs序基础上进行边权修改的策略。强调了在同一条重链中,只修改深度较深节点的边权。
413

被折叠的 条评论
为什么被折叠?



