P1505 [国家集训队]旅游
题目描述
Ray 乐忠于旅游,这次他来到了T 城。T 城是一个水上城市,一共有 N 个景点,有些景点之间会用一座桥连接。为了方便游客到达每个景点但又为了节约成本,T 城的任意两个景点之间有且只有一条路径。换句话说, T 城中只有N − 1 座桥。
Ray 发现,有些桥上可以看到美丽的景色,让人心情愉悦,但有些桥狭窄泥泞,令人烦躁。于是,他给每座桥定义一个愉悦度w,也就是说,Ray 经过这座桥会增加w 的愉悦度,这或许是正的也可能是负的。有时,Ray 看待同一座桥的心情也会发生改变。
现在,Ray 想让你帮他计算从u 景点到v 景点能获得的总愉悦度。有时,他还想知道某段路上最美丽的桥所提供的最大愉悦度,或是某段路上最糟糕的一座桥提供的最低愉悦度。
输入输出格式
输入格式:
输入的第一行包含一个整数N,表示T 城中的景点个数。景点编号为 0...N − 1。
接下来N − 1 行,每行三个整数u、v 和w,表示有一条u 到v,使 Ray 愉悦度增加w 的桥。桥的编号为1...N − 1。|w| <= 1000。 输入的第N + 1 行包含一个整数M,表示Ray 的操作数目。
接下来有M 行,每行描述了一个操作,操作有如下五种形式:
-
C i w,表示Ray 对于经过第i 座桥的愉悦度变成了w。
-
N u v,表示Ray 对于经过景点u 到v 的路径上的每一座桥的愉悦度都变成原来的相反数。
-
SUM u v,表示询问从景点u 到v 所获得的总愉悦度。
-
MAX u v,表示询问从景点u 到v 的路径上的所有桥中某一座桥所提供的最大愉悦度。
- MIN u v,表示询问从景点u 到v 的路径上的所有桥中某一座桥所提供的最小愉悦度。
测试数据保证,任意时刻,Ray 对于经过每一座桥的愉悦度的绝对值小于等于1000。
输出格式:
对于每一个询问(操作S、MAX 和MIN),输出答案。
输入输出样例
输入样例#1: 复制
3 0 1 1 1 2 2 8 SUM 0 2 MAX 0 2 N 0 1 SUM 0 2 MIN 0 2 C 1 3 SUM 0 2 MAX 0 2
输出样例#1: 复制
3 2 1 -1 5 3
说明
很容易的基础题哦>.<
// luogu-judger-enable-o2 //又是一个边权->点权 //儿子记录父亲边 //修改: //。。。。lazy标记很好打,直接改 //取反操作就让maxn=-minn,minn=-maxn //然后打个标记往下传就好了 //没有区间加减乘除,只有个取反操作,就很容易了 //不然会比较麻烦 #include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; const int N=1e5+5; const int INF=599518803; int n,m; int head[N],num_edge; struct Edge { int v,w,nxt; }edge[N<<1]; struct NODE { int fa,son; int size,dep; int s,t; int top; }node[N]; struct TREE { TREE *lson,*rson; int l,r,mid; int maxn,minn,sum; bool flag; }tree[N<<2]; typedef TREE* Tree; Tree Root,now_node=tree; inline int read() { char c=getchar();int num=0,f=1; for(;!isdigit(c);c=getchar()) f=c=='-'?-1:f; for(;isdigit(c);c=getchar()) num=num*10+c-'0'; return num*f; } inline void add_edge(int u,int v,int w) { edge[++num_edge].v=v; edge[num_edge].w=w; edge[num_edge].nxt=head[u]; head[u]=num_edge; } void dfs1(int u) { node[u].size=1; for(int i=head[u],v;i;i=edge[i].nxt) { v=edge[i].v; if(v==node[u].fa) continue; node[v].fa=u; node[v].dep=node[u].dep+1; dfs1(v); node[u].size+=node[v].size; if(node[u].son==0||node[v].size>node[node[u].son].size) node[u].son=v; } } int bound; void dfs2(int u,int top) { node[u].s=++bound; node[u].top=top; if(node[u].son) { dfs2(node[u].son,top); for(int i=head[u],v;i;i=edge[i].nxt) { v=edge[i].v; if(v==node[u].fa||v==node[u].son) continue; dfs2(v,v); } } node[u].t=bound; } void build(Tree &root,int l,int r) { root=++now_node; root->l=l,root->r=r,root->mid=l+r>>1; if(l==r) return; build(root->lson,l,root->mid); build(root->rson,root->mid+1,r); } inline void pushup(const Tree &root) { root->maxn = max(root->lson->maxn,root->rson->maxn); root->minn = min(root->lson->minn,root->rson->minn); root->sum = root->lson->sum+root->rson->sum; } inline void pushdown(const Tree &root) { if(root->flag) { root->lson->flag^=1; root->rson->flag^=1; swap(root->lson->minn,root->lson->maxn); root->lson->minn*=-1; root->lson->maxn*=-1; root->lson->sum *= -1; swap(root->rson->minn,root->rson->maxn); root->rson->minn*=-1; root->rson->maxn*=-1; root->rson->sum*=-1; // int tmp=root->lson->maxn; // root->lson->maxn=-root->lson->minn; // root->lson->minn=-tmp; // tmp=root->rson->maxn; // root->rson->maxn=-root->rson->minn; // root->rson->minn=-tmp; root->flag=0; } } void change(const Tree &root,int pos,int w) { if(root->l==root->r) { root->sum=root->maxn=root->minn=w; return; } pushdown(root); if(pos<=root->mid) change(root->lson,pos,w); else change(root->rson,pos,w); pushup(root); } void reverse(const Tree &root,int l,int r) { if(root->l==l&&root->r==r) { root->flag^=1; swap(root->minn,root->maxn); root->minn*=-1; root->maxn*=-1; root->sum*=-1; return; } pushdown(root); if(r<=root->mid) reverse(root->lson,l,r); else if(l>root->mid) reverse(root->rson,l,r); else { reverse(root->lson,l,root->mid); reverse(root->rson,root->mid+1,r); } pushup(root); } int query(const Tree &root,int l,int r) { if(l==root->l&&root->r==r) return root->sum; pushdown(root); if(r<=root->mid) return query(root->lson,l,r); else if(l>root->mid) return query(root->rson,l,r); else return query(root->lson,l,root->mid)+query(root->rson,root->mid+1,r); } int maximum(const Tree &root,int l,int r) { if(root->l==l&&root->r==r) return root->maxn; pushdown(root); if(r<=root->mid) return maximum(root->lson,l,r); else if(l>root->mid) return maximum(root->rson,l,r); else return max(maximum(root->lson,l,root->mid),maximum(root->rson,root->mid+1,r)); } int minimum(const Tree &root,int l,int r) { if(root->l==l&&root->r==r) return root->minn; pushdown(root); if(r<=root->mid) return minimum(root->lson,l,r); else if(l>root->mid) return minimum(root->rson,l,r); else return min(minimum(root->lson,l,root->mid),minimum(root->rson,root->mid+1,r)); } inline void Reverse(int x,int y) { int fx=node[x].top,fy=node[y].top; while(fx!=fy) { if(node[fx].dep>node[fy].dep) { reverse(Root,node[fx].s,node[x].s); x=node[fx].fa; fx=node[x].top; } else { reverse(Root,node[fy].s,node[y].s); y=node[fy].fa; fy=node[y].top; } } if(x==y) //轻边 return; else if(node[x].dep>node[y].dep) reverse(Root,node[y].s+1,node[x].s); else reverse(Root,node[x].s+1,node[y].s); } inline int Query(int x,int y) { int fx=node[x].top,fy=node[y].top; int ans=0; while(fx!=fy) { if(node[fx].dep>node[fy].dep) { ans+=query(Root,node[fx].s,node[x].s); x=node[fx].fa; fx=node[x].top; } else { ans+=query(Root,node[fy].s,node[y].s); y=node[fy].fa; fy=node[y].top; } } if(x==y) return ans; else if(node[x].dep>node[y].dep) return ans+query(Root,node[y].s+1,node[x].s); else return ans+query(Root,node[x].s+1,node[y].s); } inline int Maximum(int x,int y) { int fx=node[x].top,fy=node[y].top; int ans=-INF; while(fx!=fy) { if(node[fx].dep>node[fy].dep) { ans=max(ans,maximum(Root,node[fx].s,node[x].s)); x=node[fx].fa; fx=node[x].top; } else { ans=max(ans,maximum(Root,node[fy].s,node[y].s)); y=node[fy].fa; fy=node[y].top; } } if(x==y) return ans; else if(node[x].dep>node[y].dep) return max(ans,maximum(Root,node[y].s+1,node[x].s)); else return max(ans,maximum(Root,node[x].s+1,node[y].s)); } inline int Minimum(int x,int y) { int fx=node[x].top,fy=node[y].top; int ans=INF; while(fx!=fy) { if(node[fx].dep>node[fy].dep) { ans=min(ans,minimum(Root,node[fx].s,node[x].s)); x=node[fx].fa; fx=node[x].top; } else { ans=min(ans,minimum(Root,node[fy].s,node[y].s)); y=node[fy].fa; fy=node[y].top; } } if(x==y) return ans; else if(node[x].dep>node[y].dep) return min(ans,minimum(Root,node[y].s+1,node[x].s)); else return min(ans,minimum(Root,node[x].s+1,node[y].s)); } inline int choose(int num) { if(node[edge[num*2-1].v].dep>node[edge[num<<1].v].dep) return edge[num*2-1].v; else return edge[num<<1].v; } char s[5]; string a; int u,v,w; int main() { n=read(); for(int i=1;i<n;++i) { u=read(),v=read(),w=read(); add_edge(u,v,w); add_edge(v,u,w); } dfs1(0); dfs2(0,0); build(Root,1,n); for(int i=1;i<n;++i) { u=choose(i); change(Root,node[u].s,edge[i<<1].w); } m=read(); // getline(cin,a); // cout<<a<<endl; for(int i=1;i<=m;++i) { scanf("%s",s); u=read(),v=read(); if(s[0]=='C') u=choose(u), change(Root,node[u].s,v); else if(s[0]=='N') Reverse(u,v); else if(s[0]=='S') printf("%d\n",Query(u,v)); else if(s[1]=='A') printf("%d\n",Maximum(u,v)); else printf("%d\n",Minimum(u,v)); } return 0; }