Time Limit: 5000MS | Memory Limit: 131072K | |
Total Submissions: 3629 | Accepted: 1017 |
Description
You are given a tree with N nodes. The tree’s nodes are numbered 1 through N and its edges are numbered 1 through N − 1. Each edge is associated with a weight. Then you are to execute a series of instructions on the tree. The instructions can be one of the following forms:
CHANGE i v |
Change the weight of the ith edge to v |
NEGATE a b |
Negate the weight of every edge on the path from a to b |
QUERY a b |
Find the maximum weight of edges on the path from a to b |
Input
The input contains multiple test cases. The first line of input contains an integer t (t ≤ 20), the number of test cases. Then follow the test cases.
Each test case is preceded by an empty line. The first nonempty line of its contains N (N ≤ 10,000). The next N − 1 lines each contains three integers a, b and c, describing an edge connecting nodes a and bwith
weight c. The edges are numbered in the order they appear in the input. Below them are the instructions, each sticking to the specification above. A lines with the word “DONE
” ends the test case.
Output
For each “QUERY
” instruction, output the result on a separate line.
Sample Input
1 3 1 2 1 2 3 2 QUERY 1 2 CHANGE 1 3 QUERY 1 2 DONE
Sample Output
1 3
题意:给出一颗树以及边权值,对边权有三种操作:(1)把第i条边的权值改成v;(2)把<u,v>路径上的边权值改为原来的相反数;(3)输出<u,v>路径上的最大权值;
程序:
#include"stdio.h" #include"string.h" #include"iostream" #include"map" #include"string" #include"queue" #include"stdlib.h" #include"math.h" #define M 11009 #define eps 1e-10 #define inf 1000000000 #define mod 1000000000 #define INF 1000000000 using namespace std; struct node { int u,v,w,next; }edge[M*2]; int t,head[M]; int son[M];//记录重链中某点的儿子节点,子叶节点的儿子为-1; int fa[M];//记录每个节点的父节点; int num[M];//记录以该节点为根的子树中有多少个节点; int top[M];//记录某条重链中所有节点的最初节点编号; int p[M];//记录某个节点的编号(对原来的节点重新编号) int fp[M];//记录某编号的节点对应的原来的节点编号; int deep[M];//记录某个节点在树中的深度; int a[M];//记录编过号的节点与其父节点之间的边的边权值;维护的线段树是n-1个点 int pos; int Max; void init() { t=pos=0; memset(head,-1,sizeof(head)); memset(son,-1,sizeof(son)); } void add(int u,int v) { edge[t].u=u; edge[t].v=v; edge[t].next=head[u]; head[u]=t++; } void dfs(int u,int f,int d) { deep[u]=d; num[u]=1; fa[u]=f; for(int i=head[u];i!=-1;i=edge[i].next) { int v=edge[i].v; if(v!=f) { dfs(v,u,d+1); num[u]+=num[v]; if(son[u]==-1||num[son[u]]<num[v]) son[u]=v; } } } void getpos(int u,int sp) { 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=edge[i].next) { int v=edge[i].v; if(v!=fa[u]&&v!=son[u]) getpos(v,v); } }//以上是求重链 //***************************以下是线段树操作****************************// struct Node { int l,r,flag,maxi,mini; }tree[M*4]; void pushup(int i) { tree[i].maxi=max(tree[i*2].maxi,tree[i*2+1].maxi); tree[i].mini=min(tree[i*2].mini,tree[i*2+1].mini); } void pushdown(int i)//lazy操作 { if(tree[i].l==tree[i].r)return; if(tree[i].flag) { tree[i*2].maxi=-tree[i*2].maxi; tree[i*2].mini=-tree[i*2].mini; swap(tree[i*2].maxi,tree[i*2].mini); tree[i*2].flag^=1; tree[i*2+1].maxi=-tree[i*2+1].maxi; tree[i*2+1].mini=-tree[i*2+1].mini; swap(tree[i*2+1].maxi,tree[i*2+1].mini); tree[i*2+1].flag^=1; tree[i].flag=0; } } void make(int l,int r,int i)//建立线段树 { tree[i].l=l; tree[i].r=r; tree[i].flag=0; if(tree[i].l==tree[i].r) { tree[i].maxi=tree[i].mini=a[tree[i].l]; return; } int mid=(l+r)>>1; make(l,mid,i*2); make(mid+1,r,i*2+1); pushup(i); } void change(int p,int q,int i)//单点更新 { if(tree[i].l==p&&tree[i].r==p) { tree[i].maxi=tree[i].mini=q; tree[i].flag=0; return; } pushdown(i); int mid=(tree[i].l+tree[i].r)>>1; if(p<=mid)change(p,q,i*2); else change(p,q,i*2+1); pushup(i); } void negval(int l,int r,int i)//区间修改为相反数 { if(tree[i].l==l&&tree[i].r==r) { tree[i].maxi=-tree[i].maxi; tree[i].mini=-tree[i].mini; swap(tree[i].maxi,tree[i].mini); tree[i].flag^=1; return; } pushdown(i); int mid=(tree[i].l+tree[i].r)>>1; if(r<=mid) negval(l,r,i*2); else if(l>mid) negval(l,r,i*2+1); else { negval(l,mid,i*2); negval(mid+1,r,i*2+1); } pushup(i); } void query(int l,int r,int i)//区间查找 { if(tree[i].l==l&&tree[i].r==r) { Max=max(Max,tree[i].maxi); return; } pushdown(i); int mid=(tree[i].l+tree[i].r)>>1; if(r<=mid) query(l,r,i*2); else if(l>mid) query(l,r,i*2+1); else { query(l,mid,i*2); query(mid+1,r,i*2+1); } pushup(i); } int findmax(int u,int v)//树形图转换为线段树结构,并查找最大值 { int f1=top[u]; int f2=top[v]; int ans=-inf; while(f1!=f2) { if(deep[f1]<deep[f2]) { swap(f1,f2); swap(u,v); } Max=-inf; query(p[f1],p[u],1); ans=max(ans,Max); u=fa[f1]; f1=top[u]; } if(v==u)return ans; if(deep[u]>deep[v])swap(u,v); Max=-inf; query(p[son[u]],p[v],1); ans=max(ans,Max); return ans; } void neg(int u,int v)//树形图转换为线段树结构,并修改区间值 { int f1=top[u]; int f2=top[v]; while(f1!=f2) { if(deep[f1]<deep[f2]) { swap(f1,f2); swap(u,v); } negval(p[f1],p[u],1); u=fa[f1]; f1=top[u]; } if(v==u)return; if(deep[u]>deep[v])swap(u,v); negval(p[son[u]],p[v],1); return; } struct Edge { int u,v,w; }e[M]; int main() { int T,i,n; cin>>T; while(T--) { scanf("%d",&n); init(); for(i=1;i<n;i++) { scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w); add(e[i].u,e[i].v); add(e[i].v,e[i].u); } dfs(1,1,0); getpos(1,1); for(i=1;i<n;i++) { if(deep[e[i].u]<deep[e[i].v]) swap(e[i].v,e[i].u); a[p[e[i].u]]=e[i].w; } make(1,pos-1,1); char ch[22]; int x,y; while(scanf("%s",ch),strcmp(ch,"DONE")!=0) { scanf("%d%d",&x,&y); if(ch[0]=='Q') { printf("%d ",findmax(x,y)); } else if(ch[0]=='C') { change(p[e[x].u],y,1); } else neg(x,y); } } return 0; }