传送门
很明显是树链剖分,因为是边权,所以将每个边权给深度大的那个点可以了,根节点不用赋值,要求最大值和最小值,所以线段树不包含根节点。因为点是从0编号的,所以父节点和重儿子数组要初始化。
#include
#include
#include
using namespace std;
const int N=200010,inf=0x3f3f3f3f;
int n,m,a[N],b[N],c[N],h[N],e[N<<1],ne[N<<1],w[N<<1],idx,col[N];
void add(int a,int b,int c)
{
e[idx]=b;ne[idx]=h[a];w[idx]=c;h[a]=idx++;
}
struct segtree
{
struct node
{
int l,r,sum,maxx,minn,lzy;
}tr[N<<2];
void pushup(node &rt,node &l,node &r)
{
rt.sum=l.sum+r.sum;
rt.maxx=max(l.maxx,r.maxx);
rt.minn=min(l.minn,r.minn);
}
void pushdown(node &rt,node &l,node &r)
{
if(rt.lzy&1)
{
l.sum*=-1; l.maxx^=l.minn^=l.maxx^=l.minn;l.maxx*=-1;l.minn*=-1;
r.sum*=-1; r.maxx^=r.minn^=r.maxx^=r.minn;r.maxx*=-1;r.minn*=-1;
l.lzy+=rt.lzy;
r.lzy+=rt.lzy;
}
rt.lzy=0;
}
void build(int rt,int l,int r)
{
if(l==r) tr[rt]={
l,r,col[l],col[l],col[l],0};
else
{
int mid=l+r>>1;
tr[rt]={
l,r};
build(rt<<1,l,mid);
build(rt<<1|1,mid+1,r);
pushup(tr[rt],tr[rt<<1],tr[rt<<1|1]);
}
}
void updata(int rt,int l,int r,int d,int f)
{
if(l<=tr[rt].l&&r>=tr[rt].r)
{
if(f==1)//取相反数
{
tr[rt].sum*=-1;
tr[rt].maxx^=tr[rt].minn^=tr[rt].maxx^=tr[rt].minn;
tr[rt].minn*=-1;tr[rt].maxx*=-1;
tr[rt].lzy++;
}
else tr[rt].maxx=tr[rt].sum=tr[rt].minn=d;//边权赋值,单点更新
return ;
}
int mid=tr[rt].l+tr[rt].r>>1;
pushdown(tr[rt],tr[rt<<1],tr[rt<<1|1]);
if(l<=mid) updata(rt<<1,l,r,d,f);
if(r>mid) updata(rt<<1|1,l,r,d,f);
pushup(tr[rt],tr[rt<<1],tr[rt<<1|1]);
return ;
}
node query(int rt,int l,int r)
{
if(l<=tr[rt].l&&r>=tr[rt].r) return tr[rt];
int mid=tr[rt].l+tr[rt].r>>1;
pushdown(tr[rt],tr[rt<<1],tr[rt<<1|1]);
if(r<=mid) return query(rt<<1,l,r);
if(l>mid) return query(rt<<1|1,l,r);
node ans,left,right;
left=query(rt<<1,l,r);
right=query(rt<<1|1,l,r);
pushup(ans,left,right);
return ans;
}
}tree;
struct shupo
{
int top[N],dfn[N],son[N],dep[N],sz[N],fa[N],cnt;
void dfs1(int u)
{
sz[u]=1;
for(int i=h[u];i!=-1;i=ne[i])
{
int v=e[i];
if(v==fa[u]) continue;
dep[v]=dep[u]+1;
fa[v]=u;
dfs1(v);
sz[u]+=sz[v];
if(son[u]==-1) son[u]=v;
else if(sz[v]>sz[son[u]]) son[u]=v;
}
}
void dfs2(int u,int t,int c)
{
dfn[u]=++cnt;
col[cnt]=c;
top[u]=t;
for(int i=h[u];i!=-1;i=ne[i])
if(e[i]==son[u])
dfs2(son[u],t,w[i]);
for(int i=h[u];i!=-1;i=ne[i])
{
int v=e[i];
if(v==son[u]||v==fa[u]) continue;
dfs2(v,v,w[i]);
}
}
void updata_ed(int u,int d)
{
if(dep[a[u]]>dep[b[u]]) a[u]^=b[u]^=a[u]^=b[u];
tree.updata(1,dfn[b[u]],dfn[b[u]],d,0);//a[u],b[u]的时间戳不相邻!!
}
void updata_mem(int x,int y)
{
while(top[x]!=top[y])
{
if(dep[top[x]]>dep[top[y]]) x^=y^=x^=y;//swap
tree.updata(1,dfn[top[y]],dfn[y],0,1);
y=fa[top[y]];
}
if(dep[x]>dep[y]) x^=y^=x^=y;
if(dfn[x]+1<=dfn[y]) tree.updata(1,dfn[x]+1,dfn[y],0,1);//同一条链的时候深度高的那个点表示的边权不在要更新的路径上,下同
return ;
}
int query_sum(int x,int y)
{
int ans=0;
while(top[x]!=top[y])
{
if(dep[top[x]]>dep[top[y]]) x^=y^=x^=y;
ans+=tree.query(1,dfn[top[y]],dfn[y]).sum;
y=fa[top[y]];
}
if(dep[x]>dep[y]) x^=y^=x^=y;
if(dfn[x]+1<=dfn[y]) ans+=tree.query(1,dfn[x]+1,dfn[y]).sum;
return ans;
}
int query_max(int x,int y)
{
int ans=-inf;
while(top[x]!=top[y])
{
if(dep[top[x]]>dep[top[y]]) x^=y^=x^=y;
ans=max(ans,tree.query(1,dfn[top[y]],dfn[y]).maxx);
y=fa[top[y]];
}
if(dep[x]>dep[y]) x^=y^=x^=y;
if(dfn[x]+1<=dfn[y]) ans=max(ans,tree.query(1,dfn[x]+1,dfn[y]).maxx);
return ans;
}
int query_min(int x,int y)
{
int ans=inf;
while(top[x]!=top[y])
{
if(dep[top[x]]>dep[top[y]]) x^=y^=x^=y;
ans=min(ans,tree.query(1,dfn[top[y]],dfn[y]).minn);
y=fa[top[y]];
}
if(dep[x]>dep[y]) x^=y^=x^=y;
if(dfn[x]+1<=dfn[y]) ans=min(ans,tree.query(1,dfn[x]+1,dfn[y]).minn);
return ans;
}
}T;
int main()
{
memset(h,-1,sizeof h);
memset(T.son,-1,sizeof T.son);
memset(T.fa,-1,sizeof T.fa);
scanf("%d",&n);
for(int i=1;i<n;i++)
{
scanf("%d%d%d",a+i,b+i,c+i);
add(a[i],b[i],c[i]);
add(b[i],a[i],c[i]);
}
T.dfs1(0);
T.dfs2(0,0,0);
tree.build(1,2,n);
scanf("%d",&m);
char op[5];
int x,y;
while(m--)
{
scanf("%s%d%d",op,&x,&y);
if(*op=='C') T.updata_ed(x,y);
else if(*op=='N') T.updata_mem(x,y);
else if(*op=='S') printf("%d\n",T.query_sum(x,y));
else if(op[1]=='A') printf("%d\n",T.query_max(x,y));
else printf("%d\n",T.query_min(x,y));
}
return 0;
}