关于旅游这个题需要注意的小点
因为这个题细节有些多,所以写了一下注意的点,具体思路的话是个模板
会树剖的话应该都会写
#include<iostream>
#include<cstdio>
#define l(o) (o<<1)
#define r(o) (o<<1|1)
#define mid ((l+r)>>1)
using namespace std;
const int N=2e5+7;
struct edge{
int v,w,nxt;
}e[N<<1];
int n,m,cnt;
int head[N],dep[N],top[N],siz[N],fa[N],minn[N],maxn[N],sum[N],tag[N],hs[N],w[N],dfn[N],a[N],from[N],to[N];
void add_edge(int u,int v,int w){
cnt++;
e[cnt].v=v;
e[cnt].w=w;
e[cnt].nxt=head[u];
head[u]=cnt;
}
void get_tree(int u){
dep[u]=dep[fa[u]]+1;
siz[u]=1;
for(int i=head[u];i;i=e[i].nxt){
int to=e[i].v;
if(to!=fa[u]){
fa[to]=u;
get_tree(to);
w[to]=e[i].w;
siz[u]+=siz[to];
if(siz[hs[u]]<siz[to])hs[u]=to;
}
}
}
void dfs(int u,int fat){
top[u]=fat;
dfn[u]=++cnt;
a[dfn[u]]=w[u];
if(hs[u])dfs(hs[u],fat);
for(int i=head[u];i;i=e[i].nxt){
int to=e[i].v;
if(to!=fa[u]&&to!=hs[u]){
dfs(to,to);
}
}
}
void up(int o){
sum[o]=sum[l(o)]+sum[r(o)];
maxn[o]=max(maxn[l(o)],maxn[r(o)]);
minn[o]=min(minn[l(o)],minn[r(o)]);
}
void build(int o,int l,int r){
if(l==r){
sum[o]=maxn[o]=minn[o]=a[l];
return ;
}
build(l(o),l,mid);build(r(o),mid+1,r);
up(o);
}
//注意线段树标记的更改,自己本身取反,并把标记取反(注意:标记对自己本身没有影响,有影响的是他的子树);
void modify(int o){
sum[o]=-sum[o];
int t=maxn[o];
maxn[o]=-minn[o];
minn[o]=-t;
}
void down(int o,int l,int r){
if(tag[o]){
tag[l(o)]^=1,tag[r(o)]^=1;
modify(l(o));
modify(r(o));
tag[o]=0;
}
}
void change(int o,int l,int r,int L,int R){
if(L<=l&&R>=r){
tag[o]^=1;
modify(o);
return ;
}
down(o,l,r);
if(L<=mid)change(l(o),l,mid,L,R);
if(R>mid)change(r(o),mid+1,r,L,R);
up(o);
}
void chenge(int o,int l,int r,int k,int val){
if(l==r){
sum[o]=maxn[o]=minn[o]=val;
return ;
}
down(o,l,r);
if(k<=mid)chenge(l(o),l,mid,k,val);
else chenge(r(o),mid+1,r,k,val);
up(o);
}
int ask(int o,int l,int r,int L,int R,int val){
if(L<=l&&R>=r){
if(val==1)return sum[o];
if(val==2)return maxn[o];
if(val==3)return minn[o];
}
down(o,l,r);
int res=0;
if(val==1){
if(L<=mid)res+=ask(l(o),l,mid,L,R,val);
if(R>mid)res+=ask(r(o),mid+1,r,L,R,val);
return res;
}
if(val==2){
res=-233333333;
if(L<=mid)res=max(res,ask(l(o),l,mid,L,R,val));
if(R>mid)res=max(res,ask(r(o),mid+1,r,L,R,val));
return res;
}
if(val==3){
res=23333333;
if(L<=mid)res=min(res,ask(l(o),l,mid,L,R,val));
if(R>mid)res=min(res,ask(r(o),mid+1,r,L,R,val));
return res;
}
}
void solve(int x,int y,int val){
int ans=0;
if(val==3) ans=23333333;
if(val==2) ans=-23333333;//注意可能有负边权;
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])swap(x,y);
if(val==4){
change(1,1,n,dfn[top[x]],dfn[x]);
}else{
if(val==1)ans+=ask(1,1,n,dfn[top[x]],dfn[x],val);
if(val==2)ans=max(ans,ask(1,1,n,dfn[top[x]],dfn[x],val));
if(val==3)ans=min(ans,ask(1,1,n,dfn[top[x]],dfn[x],val));
}
x=fa[top[x]];
}
if(dfn[x]>dfn[y])swap(x,y);
if(val==4)change(1,1,n,dfn[x]+1,dfn[y]);
if(val==1)ans+=ask(1,1,n,dfn[x]+1,dfn[y],val);
if(val==2)ans=max(ans,ask(1,1,n,dfn[x]+1,dfn[y],val));//注意边转点的题dfn+1;
if(val==3)ans=min(ans,ask(1,1,n,dfn[x]+1,dfn[y],val));//不能在这里赋初值
if(val>=1&&val<=3)cout<<ans<<"\n";
}
int main(){
scanf("%d",&n);
for(int i=1;i<n;i++){
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
add_edge(x+1,y+1,z);
add_edge(y+1,x+1,z);
from[i]=x+1;to[i]=y+1;
}
cnt=0;
get_tree(1);
dfs(1,1);
build(1,1,n);
scanf("%d",&m);
// for(int i = 1; i <=n; i ++){
// cout<<ask(1,1,n,dfn[i],dfn[i],1)<<"\n";
// }
while(m--){
char opt[5];
int x,y;
scanf("%s",opt+1);
scanf("%d%d",&x,&y);
if(opt[1]=='C'){
if(fa[from[x]]==to[x])chenge(1,1,n,dfn[from[x]],y);//注意是dfn,注意这里的x,y不用加1;
else chenge(1,1,n,dfn[to[x]],y);
continue;
}
x+=1;y+=1;//在这里加一;
if(opt[1]=='N'){
solve(x,y,4);
continue;
}
if(opt[1]=='S'){
//cout<<"1"<<"\n";
solve(x,y,1);
continue;
}
if(opt[2]=='A'){
solve(x,y,2);
continue;
}
if(opt[2]=='I'){
solve(x,y,3);
}
}
}