标签:
题目大意:
指定一颗树上有3个操作:
询问操作,询问a点和b点之间的路径上最长的那条边的长度;
取反操作,将a点和b点之间的路径权值都取相反数;
变化操作,把某条边的权值变成指定的值。
#include <iostream> #include <algorithm> #include <cstring> #include <cmath> #include <queue> #include <map> #include <set> #include <vector> #include <cstdio> using namespace std; const int N=100010; struct Edge { int to,next; }eg[N*2]; int head[N],tot; int top[N];//top[v]表示v所在的重链的顶端节点 int fa[N];//父亲节点 int deep[N];//深度 int num[N];//num[v]表示以v为根的子树的节点数 int p[N];//p[v]表示v与其父亲节点的连边在线段树中的位置 int fp[N];//和p数组相反 int son[N];//重儿子 int pos; void init() { tot=0; memset(head,-1,sizeof(head)); pos=0; memset(son,-1,sizeof(son)); } void add(int u,int v) { eg[tot].to=v; eg[tot].next=head[u]; head[u]=tot++; } void dfs1(int u,int pre,int d)//第一遍dfs求出fa,deep,num,son { deep[u]=d; fa[u]=pre; num[u]=1; for(int i=head[u];i!=-1;i=eg[i].next) { int v=eg[i].to; if(v!=pre) { dfs1(v,u,d+1); num[u]+=num[v]; if(son[u]==-1||num[v]>num[son[u]]) son[u]=v; } } } void getpos(int u,int sp)//第二遍dfs求出top和p { top[u]=sp; p[u]=pos++; fp[p[u]]=u; if(son[u]==-1) return ; getpos(son[u],sp); for(int i=head[u];i!=-1;i=eg[i].next) { int v=eg[i].to; if(v!=son[u]&&v!=fa[u]) getpos(v,v); } } //线段树 struct Node { int l,r,ma,mi,ne; }tree[N*3]; void build(int i,int l,int r) { tree[i].l=l; tree[i].r=r; tree[i].ma=tree[i].mi=tree[i].ne=0; if(l==r) return ; int mid=(l+r)>>1; build(i<<1,l,mid); build(i<<1|1,mid+1,r); } void pushup(int i) { tree[i].mi=min(tree[i<<1].mi,tree[i<<1|1].mi); tree[i].ma=max(tree[i<<1].ma,tree[i<<1|1].ma); } void pushdown(int i) { if(tree[i].l==tree[i].r) return ; if(tree[i].ne) { tree[i<<1].ma=-tree[i<<1].ma; tree[i<<1].mi=-tree[i<<1].mi; swap(tree[i<<1].ma,tree[i<<1].mi); tree[i<<1|1].ma=-tree[i<<1|1].ma; tree[i<<1|1].mi=-tree[i<<1|1].mi; swap(tree[i<<1|1].ma,tree[i<<1|1].mi); tree[i<<1].ne^=1; tree[i<<1|1].ne^=1; tree[i].ne=0; } } void update(int i,int k,int val)//更新线段树的第k个值为val { if(tree[i].l==k&&tree[i].r==k) { tree[i].ma=tree[i].mi=val; tree[i].ne=0; return ; } pushdown(i); int mid=(tree[i].l+tree[i].r)>>1; if(k<=mid) update(i<<1,k,val); else update(i<<1|1,k,val); pushup(i); } void ne_update(int i,int l,int r)//更新线段树的区间[l,r]取反 { if(tree[i].l==l&&tree[i].r==r) { tree[i].ma=-tree[i].ma; tree[i].mi=-tree[i].mi; swap(tree[i].ma,tree[i].mi); tree[i].ne^=1; return ; } pushdown(i); int mid=(tree[i].l+tree[i].r)>>1; if(r<=mid) ne_update(i<<1,l,r); else if(l>mid) ne_update(i<<1|1,l,r); else { ne_update(i<<1,l,mid); ne_update(i<<1|1,mid+1,r); } pushup(i); } int query(int i,int l,int r)//查询线段树中[l,r]的最大值 { if(tree[i].l==l&&tree[i].r==r) return tree[i].ma; pushdown(i); int mid=(tree[i].l+tree[i].r)>>1; if(r<=mid) return query(i<<1,l,r); else if(l>mid) return query(i<<1|1,l,r); else return max(query(i<<1,l,mid),query(i<<1|1,mid+1,r)); pushup(i); } int find(int u,int v)//查询u->v边的最大值 { int f1=top[u],f2=top[v],tmp=-100000000; while(f1!=f2) { if(deep[f1]<deep[f2]) { swap(f1,f2); swap(u,v); } tmp=max(tmp,query(1,p[f1],p[u])); u=fa[f1]; f1=top[u]; } if(u==v) return tmp; if(deep[u]>deep[v]) swap(u,v); return max(tmp,query(1,p[son[u]],p[v])); } void nega(int u,int v)//把u-v路径上的边的值都设置为val { int f1=top[u],f2=top[v]; while(f1!=f2) { if(deep[f1]<deep[f2]) { swap(f1,f2); swap(u,v); } ne_update(1,p[f1],p[u]); u=fa[f1]; f1=top[u]; } if(u==v) return ; if(deep[u]>deep[v]) swap(u,v); return ne_update(1,p[son[u]],p[v]); } int e[N][3]; int main() { //freopen("in.txt","r",stdin); int t,n; scanf("%d",&t); while(t--) { init(); scanf("%d",&n); for(int i=0;i<n-1;i++) { scanf("%d%d%d",&e[i][0],&e[i][1],&e[i][2]); add(e[i][0],e[i][1]); add(e[i][1],e[i][0]); } dfs1(1,0,0); getpos(1,1); build(1,0,pos-1); for(int i=0;i<n-1;i++) { if(deep[e[i][0]]>deep[e[i][1]]) swap(e[i][0],e[i][1]); update(1,p[e[i][1]],e[i][2]); } char op[10]; int u,v; while(scanf("%s",op)) { if(op[0]==‘D‘) break; scanf("%d%d",&u,&v); if(op[0]==‘Q‘) printf("%d\n",find(u,v));//查询u->v路径上边权的最大值 else if(op[0]==‘N‘) nega(u,v); else update(1,p[e[u-1][1]],v);//修改第u条边的长度为v } } return 0; }
标签:
原文地址:http://www.cnblogs.com/d-e-v-i-l/p/5027340.html