树链剖分维护的都是点,而这道题要求的是边。
解决:就把边权下放,变成点权,注意下放后查询u到v的路径时要除去lca的点权,因为lca的点权是其父亲的边权
细节:线段树的加标记与等于标记的维护与下传
#include<bits/stdc++.h> using namespace std; #define N 100005 #define mid ((l+r)>>1) int mx[N*4],fl[N*4],eq[N*4],n; int head[N],to[N<<1],nex[N<<1],w[N<<1],tot=0; int cnt=0,id[N],dfn[N],val[N],siz[N],dep[N],fa[N],son[N],top[N]; struct node{ int a,b; } e[N<<1]; void add(int a,int b,int c) { to[++tot]=b; nex[tot]=head[a]; head[a]=tot; w[tot]=c; } void update(int s) { mx[s]=max(mx[s<<1],mx[s<<1|1]); } void pushdown(int s)//优先处理=标记 { if(eq[s]!=-1){ fl[s<<1]=fl[s<<1|1]=0; mx[s<<1]=mx[s<<1|1]=eq[s<<1]=eq[s<<1|1]=eq[s]; eq[s]=-1; } else if(fl[s]){ fl[s<<1]+=fl[s]; fl[s<<1|1]+=fl[s]; mx[s<<1]+=fl[s]; mx[s<<1|1]+=fl[s]; fl[s]=0; } } void build(int s,int l,int r) { fl[s]=0; eq[s]=-1; if(l==r) { mx[s]=dfn[l]; return ; } build(s<<1,l,mid); build(s<<1|1,mid+1,r); update(s); } void modify_point(int s,int l,int r,int pos,int v) { if(l==r) { mx[s]=v; fl[s]=0; eq[s]=v; return ; }//eq=v?? pushdown(s); if(pos<=mid) modify_point(s<<1,l,mid,pos,v); else modify_point(s<<1|1,mid+1,r,pos,v); update(s); } void modify_add(int s,int l,int r,int L,int R,int v) { if(L<=l&&r<=R) { mx[s]+=v; fl[s]+=v; return ; } pushdown(s); if(L<=mid) modify_add(s<<1,l,mid,L,R,v); if(R>mid) modify_add(s<<1|1,mid+1,r,L,R,v); update(s); } void modify_cover(int s,int l,int r,int L,int R,int v) { //printf("%d %d\n",l,r); if(L<=l&&r<=R) { mx[s]=eq[s]=v; fl[s]=0; return ; } pushdown(s); if(L<=mid) modify_cover(s<<1,l,mid,L,R,v); if(R>mid) modify_cover(s<<1|1,mid+1,r,L,R,v); update(s); } int query(int s,int l,int r,int L,int R) { int ans=0; if(L<=l&&r<=R) return mx[s]; pushdown(s); if(L<=mid) ans=max(ans,query(s<<1,l,mid,L,R)); if(R>mid) ans=max(ans,query(s<<1|1,mid+1,r,L,R)); return ans; } void dfs1(int u,int f) { siz[u]=1; for(int i=head[u];i;i=nex[i]){ int v=to[i]; if(v==f) continue; fa[v]=u; dep[v]=dep[u]+1; val[v]=w[i]; dfs1(v,u); siz[u]+=siz[v]; if(siz[son[u]]<siz[v]) son[u]=v; } } void dfs2(int u,int tp) { id[u]=++cnt; dfn[cnt]=val[u]; top[u]=tp; if(son[u]) dfs2(son[u],tp); for(int i=head[u];i;i=nex[i]){ int v=to[i]; if(v==fa[u]||v==son[u]) continue; dfs2(v,v); } } void modify1(int i,int ww) { if(fa[e[i].a]==e[i].b) modify_point(1,1,n,id[e[i].a],ww); else modify_point(1,1,n,id[e[i].b],ww); } void modify2(int a,int b,int ww,bool op) { while(top[a]!=top[b]){ if(dep[top[a]]<dep[top[b]]) swap(a,b); if(op) modify_add(1,1,n,id[top[a]],id[a],ww); else modify_cover(1,1,n,id[top[a]],id[a],ww); a=fa[top[a]]; } if(dep[a]<dep[b]) swap(a,b); if(op) modify_add(1,1,n,id[b]+1,id[a],ww);//+1是为了保证没有算到lca那一条边!! id[b]+1 else modify_cover(1,1,n,id[b]+1,id[a],ww);//要记得+1!! } int query_link(int a,int b) { int ans=0; while(top[a]!=top[b]){ if(dep[top[a]]<dep[top[b]]) swap(a,b); ans=max(ans,query(1,1,n,id[top[a]],id[a])); a=fa[top[a]]; } if(dep[a]<dep[b]) swap(a,b); ans=max(ans,query(1,1,n,id[b]+1,id[a]));// return ans; } char op[10]; int main() { int a,b,c,x; scanf("%d",&n); for(int i=1;i<=n-1;++i) scanf("%d%d%d",&e[i].a,&e[i].b,&c),add(e[i].a,e[i].b,c),add(e[i].b,e[i].a,c); dfs1(1,0); dfs2(1,1); build(1,1,n); while(1){ scanf("%s",op); if(op[0]=='S') break; scanf("%d%d",&a,&b); if(op[0]=='C'&&op[1]=='h') modify1(a,b); else if(op[0]=='C') scanf("%d",&x),modify2(a,b,x,0); else if(op[0]=='A') scanf("%d",&x),modify2(a,b,x,1); else printf("%d\n",query_link(a,b)); } } /* 10 1 6 0 2 10 8 3 5 8 4 9 1 5 8 3 6 7 1 7 5 0 9 2 8 10 6 0 Cover 5 9 1 Max 7 10 Add 4 2 5 Change 2 6 Add 9 2 8 Change 3 6 Max 1 6 Cover 2 7 3 Max 7 9 Cover 5 8 5 Stop ans 1 0 14 */