关于旅游这个题需要注意的小点

因为这个题细节有些多,所以写了一下注意的点,具体思路的话是个模板
会树剖的话应该都会写

#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);
		}
	}
}
posted @ 2020-07-31 10:37  Aswert  阅读(128)  评论(6编辑  收藏  举报