题目大意:
直接传送门:
题解
树剖毒瘤题。
若您不会树剖,可以看yzhang神仙的讲解
这是一道很有技巧性的树剖题:
-
边权 v.s. 点权:
这道题乍一看和往常的树剖不一样:权值在边上而不在点上这时候我们应该对树进行一些转化,
先让其变为一颗有根树,
让每一个边和儿子一一对应。
如图所示:
还有一点要注意,
例如求这一条红色链的权值:
黄色的点是对应的点,不能将绿点(即\(lca\))算进去
-
线段树取负操作时,最大值和最小值互换在取负。标记为取负标记。
代码如下所示:
#include<bits/stdc++.h> #define mp make_pair #define pb push_back #define lson(id) (id<<1) #define rson(id) (id<<1|1) using namespace std; typedef long long ll; typedef unsigned long long ull; typedef vector<int > vi; typedef pair<int ,int > pii; typedef vector<pii> vii; const int inf=2e9, maxn=40007, mod=1e9+7; const ll linf=0x3f3f3f3f3f3f3f3fLL; const ll P=19260817; int n; struct edge{ int v,nxt,val; }e[maxn<<1]; int head[maxn],tot; inline void addedge(int u,int v,int val){ e[++tot].v=v; e[tot].val=val; e[tot].nxt=head[u]; head[u]=tot; } int son[maxn],top[maxn],w[maxn],size[maxn],fa[maxn],dep[maxn],num[maxn],a[maxn]; int cnt=0; void dfs1(int u,int f){ dep[u]=dep[f]+1; fa[u]=f; size[u]=1; for(int i=head[u];i;i=e[i].nxt){ int v=e[i].v; if(v==f)continue; w[v]=e[i].val; dfs1(v,u); size[u]+=size[v]; if(son[u]==0||size[v]>size[son[u]])son[u]=v; } } void dfs2(int u,int t){ top[u]=t; num[u]=++cnt;a[cnt]=w[u]; if(son[u])dfs2(son[u],t); for(int i=head[u];i;i=e[i].nxt){ int v=e[i].v; if(v==son[u]||v==fa[u])continue; dfs2(v,v); } } struct treeNode{ int sum,Min,Max; }tree[maxn<<2]; int lazy[maxn<<2]; void pushUp(int id){ tree[id].sum=tree[lson(id)].sum+tree[rson(id)].sum; tree[id].Max=max(tree[lson(id)].Max,tree[rson(id)].Max); tree[id].Min=min(tree[lson(id)].Min,tree[rson(id)].Min); } void change(int id){ tree[id].sum= -(tree[id].sum); int Maxa=tree[id].Max,Mina=tree[id].Min; tree[id].Max=-Mina,tree[id].Min=-Maxa; lazy[id]^=1; } void pushDown(int id){ if(lazy[id]){ change(lson(id)),change(rson(id)); lazy[id]=0; } } void build(int id,int l,int r){ if(l==r){ tree[id].sum=tree[id].Max=tree[id].Min=a[l]; return; } int mid=(l+r)>>1; build(lson(id),l,mid); build(rson(id),mid+1,r); pushUp(id); } void modify(int id,int l,int r,int pos,int val){ if(l==r){ tree[id].sum=tree[id].Max=tree[id].Min=val; return ; } pushDown(id); int mid=(l+r)>>1; if(pos<=mid)modify(lson(id),l,mid,pos,val); else modify(rson(id),mid+1,r,pos,val); pushUp(id); } void update(int id,int l,int r,int L,int R){ if(L<=l&&r<=R){ change(id); return ; } pushDown(id); int mid=(l+r)>>1; if(L<=mid)update(lson(id), l ,mid,L,R); if(R>mid) update(rson(id),mid+1, r ,L,R); pushUp(id); } int querySum(int id,int l,int r,int L,int R){ if(L<=l&&r<=R){ return tree[id].sum; } pushDown(id); int mid=(l+r)>>1; int ans=0; if(L<=mid)ans+=querySum(lson(id),l,mid,L,R); if(R>mid)ans+=querySum(rson(id),mid+1,r,L,R); return ans; } int queryMax(int id,int l,int r,int L,int R){ if(L<=l&&r<=R){ return tree[id].Max; } pushDown(id); int mid=(l+r)>>1; int ans=-inf; if(L<=mid)ans=max(ans,queryMax(lson(id),l,mid,L,R)); if(R>mid)ans=max(ans,queryMax(rson(id),mid+1,r,L,R)); return ans; } int queryMin(int id,int l,int r,int L,int R){ if(L<=l&&r<=R){ return tree[id].Min; } pushDown(id); int mid=(l+r)>>1; int ans=inf; if(L<=mid)ans=min(ans,queryMin(lson(id),l,mid,L,R)); if(R>mid)ans=min(ans,queryMin(rson(id),mid+1,r,L,R)); return ans; } int queryRangeSum(int x,int y){ int ans=0; while(top[x]!=top[y]){ if(dep[top[x]]<dep[top[y]])swap(x,y); ans+=querySum(1,1,n,num[top[x]],num[x]); x=fa[top[x]]; } if(dep[x]>dep[y])swap(x,y); if(x!=y)ans+=querySum(1,1,n,num[x]+1,num[y]); return ans; } int queryRangeMax(int x,int y){ int ans=-inf; while(top[x]!=top[y]){ if(dep[top[x]]<dep[top[y]])swap(x,y); ans=max(ans,queryMax(1,1,n,num[top[x]],num[x])); x=fa[top[x]]; } if(dep[x]>dep[y])swap(x,y); if(x!=y)ans=max(ans,queryMax(1,1,n,num[x]+1,num[y])); return ans; } int queryRangeMin(int x,int y){ int ans=inf; while(top[x]!=top[y]){ if(dep[top[x]]<dep[top[y]])swap(x,y); ans=min(ans,queryMin(1,1,n,num[top[x]],num[x])); x=fa[top[x]]; } if(dep[x]>dep[y])swap(x,y); if(x!=y)ans=min(ans,queryMin(1,1,n,num[x]+1,num[y])); return ans; } void updateRange(int x,int y){ while(top[x]!=top[y]){ if(dep[top[x]]<dep[top[y]])swap(x,y); update(1,1,n,num[top[x]],num[x]); x=fa[top[x]]; } if(dep[x]>dep[y])swap(x,y); if(x!=y)update(1,1,n,num[x]+1,num[y]); } int U[maxn],V[maxn]; int main(){ scanf("%d",&n); for(int i=1;i<=n-1;i++){ int u,v,w; scanf("%d%d%d",&u,&v,&w); u++,v++; U[i]=u,V[i]=v; addedge(u,v,w); addedge(v,u,w); } dfs1(1,0); dfs2(1,1); build(1,1,n); for(int i=1;i<=n-1;i++)V[i]=(dep[U[i]]<dep[V[i]]?V[i]:U[i]); int m; scanf("%d",&m); while(m--){ char op[50]; int x,y; scanf("%s%d%d",op,&x,&y); if(op[0]=='C')modify(1,1,n,num[V[x]],y); else if(op[0]=='N')updateRange(x+1,y+1); else if(op[0]=='S')printf("%d\n",queryRangeSum(x+1,y+1)); else if(op[1]=='A')printf("%d\n",queryRangeMax(x+1,y+1)); else if(op[1]=='I')printf("%d\n",queryRangeMin(x+1,y+1)); } return 0; }