Time Limit: 5000MS | Memory Limit: 131072K | |
Total Submissions: 3587 | Accepted: 1004 |
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 b with 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
Source
题意:给一棵树,三种操作。将第i条边的权值改为v,将a到b的路径上的边的权值全部取反,求a到b路径上边的权值的最大值。
思路:明显的树链剖分,加上线段树的操作。因为有取反的操作所以每个区间要记录最大值和最小值。查询两点间的路径时,用求公共祖先的方式去求。
#include<stdio.h>
#include<algorithm>
#include<string.h>
#define N 20005
#define inf 0x3fffffff
using namespace std;
struct line
{
int x,y,w;
}ed[N];
struct node
{
int u,v,w,next;
}bian[N*2];
struct pp
{
int x,y,ma,mi,p;
}a[N*3];
int e,id;
int sz[N],dep[N],head[N],top[N],son[N],father[N],ti[N];
int max(int a,int b)
{
return a>b?a:b;
}
int min(int a,int b)
{
return a<b?a:b;
}
void add(int u,int v,int w)
{
bian[e].u=u;
bian[e].v=v;
bian[e].w=w;
bian[e].next=head[u];
head[u]=e++;
}
void dfs1(int u,int fa)
{
int i,v;
sz[u]=1; dep[u]=dep[fa]+1; son[u]=0; father[u]=fa;
for(i=head[u];i!=-1;i=bian[i].next)
{
v=bian[i].v;
if(v==fa) continue;
dfs1(v,u);
sz[u]+=sz[v];
if(sz[son[u]]<sz[v])
son[u]=v;
}
}
void dfs2(int u,int fa)
{
int i,v;
top[u]=fa;
ti[u]=id++;
if(son[u]!=0)
dfs2(son[u],fa);
for(i=head[u];i!=-1;i=bian[i].next)
{
v=bian[i].v;
if(v==son[u]||v==father[u])
continue;
dfs2(v,v);
}
}
void pushdown(int t)
{
int temp=t<<1;
a[t].ma=max(a[temp].ma,a[temp+1].ma);
a[t].mi=min(a[temp].mi,a[temp+1].mi);
}
void build(int t ,int x,int y)
{
a[t].x=x; a[t].y=y; a[t].ma=a[t].mi=a[t].p=0;
if(x==y) return;
int mid=(x+y)>>1,temp=t<<1;
build(temp,x,mid);
build(temp+1,mid+1,y);
}
void find(int t)
{
int temp=t<<1;
if(a[t].p)
{
a[temp].ma=-a[temp].ma; a[temp].mi=-a[temp].mi;
swap(a[temp].ma,a[temp].mi);
a[temp+1].ma=-a[temp+1].ma; a[temp+1].mi=-a[temp+1].mi;
swap(a[temp+1].ma,a[temp+1].mi);
a[temp].p^=1;
a[temp+1].p^=1;
a[t].p=0;
}
}
int query(int t,int x,int y)//查询线段树中[x,y]的最大值
{
int ma;
if(a[t].x==x&&a[t].y==y)
return a[t].ma;
int mid=(a[t].x+a[t].y)>>1,temp=t<<1;
find(t);
if(y<=mid)
return query(temp,x,y);
else if(x>mid)
return query(temp+1,x,y);
else
return max(query(temp,x,mid),query(temp+1,mid+1,y));
}
int lca(int x,int y)//返回最大值
{
int ans;
ans=-inf;
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]])
swap(x,y);
ans=max(ans,query(1,ti[top[x]],ti[x]));
x=father[top[x]];
}
if(dep[x]>dep[y])
swap(x,y);
if(x!=y)
ans=max(ans,query(1,ti[x]+1,ti[y]));
return ans;
}
void update(int t ,int x,int w)//更新线段树的第x个值为w
{
if(a[t].x==a[t].y)
{
a[t].ma=a[t].mi=w;
a[t].p=0;
return;
}
int mid=(a[t].x+a[t].y)>>1,temp=t<<1;
find(t);
if(x<=mid)
update(temp,x,w);
else
update(temp+1,x,w);
pushdown(t);
}
void reupdate(int t,int x,int y)//更新线段树的区间[x,y]取反
{
if(a[t].x==x&&a[t].y==y)
{
a[t].ma=-a[t].ma; a[t].mi=-a[t].mi;
swap(a[t].ma,a[t].mi);
a[t].p^=1;
return ;
}
int mid=(a[t].x+a[t].y)>>1,temp=t<<1;
find(t);
if(y<=mid)
reupdate(temp,x,y);
else if(x>mid)
reupdate(temp+1,x,y);
else
{
reupdate(temp,x,mid);
reupdate(temp+1,mid+1,y);
}
pushdown(t);
}
void relca(int x,int y)//把x到y路径上的值都取反
{
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]])
swap(x,y);
reupdate(1,ti[top[x]],ti[x]);
x=father[top[x]];
}
if(dep[x]>dep[y])
swap(x,y);
if(x!=y)
reupdate(1,ti[x]+1,ti[y]);
}
int main()
{
int t,i,x,y,v,n;
char str[100];
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
e=0; memset(head,-1,sizeof(head));
for(i=1;i<n;i++)
{
scanf("%d%d%d",&ed[i].x,&ed[i].y,&ed[i].w);
add(ed[i].x,ed[i].y,ed[i].w);
add(ed[i].y,ed[i].x,ed[i].w);
}
dep[1]=0; id=1; sz[0]=0;
dfs1(1,1);
dfs2(1,1);
//for(i=1;i<=n;i++)
// printf("i=%d size=%d top=%d father=%d son=%d ti=%d dep=%d\n",i,sz[i],top[i],father[i],son[i],ti[i],dep[i]);
build(1,1,n);
for(i=1;i<n;i++)
{
if(dep[ed[i].x]<dep[ed[i].y])
swap(ed[i].x,ed[i].y);
update(1,ti[ed[i].x],ed[i].w);
}
while(scanf("%s",str),strcmp(str,"DONE")!=0)
{
if(str[0]=='Q')
{
scanf("%d%d",&x,&y);
printf("%d\n",lca(x,y));//查询x->y路径上边权的最大值
}
else if(str[0]=='N')
{
scanf("%d%d",&x,&y);
relca(x,y);
}
else if(str[0]=='C')
{
scanf("%d%d",&i,&v);//改变第i条边的值为v
update(1,ti[ed[i].x],v);
}
}
}
return 0;
}