Description
原题意太恶心,我重新整理一个吧。。
有n个点,n-1条边(一棵树),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。
注意,修改是单边修改并不是单点,还有点的编号是从0到n-1,这是这道题最大的难点(雾
SimpleInput
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
SimpleOutput
3
2
1
-1
5
3
首先大的方向,这题是在树上做操作,同时有修改,求极值等操作,妥妥树剖没得说。
那么对于每一个操作来讲一下做法吧!
1、修改
首先要注意是单边修改,不是单点修改。 那么我们平常学的树剖是单点修改,如何把单边修改等价于单点修改呢?
我们只要将一条边等效于他两端的两个点深度较大的那一个。为什么不是深度较小的那个呢?
因为这样的话点和边就无法一一对应了,如果选深度较大的那个对应,点和边就可以一一对应。
2、成段取反
打lazy标记,同时最大值和最小值互换(相反数嘛)
3、4、5、区间求和,最大值,最小值
这三个操作都是类似的,维护三个值即可。
总结:
RE了很久然后WA了很久,
最后找了班里有权限号的同学要了数据wwww
不要数据估计还要好久、、
两个教训:
1、不要手贱交换一下输入数据里面的u、v,
2、solve里面(x==y)时,如果操作的是边,不要手贱再去维护一下,因为我们把边的值放在深度较深的点上,如果这是后再去维护就是维护的上面那条边的值。
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=310000;
struct node
{
int x,y,c,next;
}a[maxn*2]; int len,last[maxn];
void ins(int x,int y,int c)
{
len++;
a[len].x=x;a[len].y=y;a[len].c=c;
a[len].next=last[x];last[x]=len;
}
int fa[maxn],dep[maxn],son[maxn],tot[maxn];
int pre_tree_node(int x)
{
son[x]=0,tot[x]=1;
for(int k=last[x];k;k=a[k].next)
{
int y=a[k].y;
if(y!=fa[x])
{
fa[y]=x;
dep[y]=dep[x]+1;
pre_tree_node(y);
if(tot[son[x]]<tot[y]) son[x]=y;
tot[x]+=tot[y];
}
}
}
int ys[maxn],z,top[maxn];
void pre_tree_edge(int x,int tp)
{
ys[x]=++z; top[x]=tp;
if(son[x]!=0) {pre_tree_edge(son[x],tp);}
for(int k=last[x];k;k=a[k].next)
{
int y=a[k].y;
if(y!=fa[x] && y!=son[x])
{
pre_tree_edge(y,y);
}
}
}
struct trnode
{
int lc,rc,l,r;
int sum;
int mx,mn;
bool gg;
}tr[maxn*4]; int trlen;
void fz(int now)
{
int lc=tr[now].lc,rc=tr[now].rc;
swap(tr[lc].mx,tr[lc].mn);
tr[lc].mx*=-1;
tr[lc].mn*=-1;
tr[lc].sum*=-1;
swap(tr[rc].mx,tr[rc].mn);
tr[rc].mx*=-1;
tr[rc].mn*=-1;
tr[rc].sum*=-1;
tr[lc].gg^=1,tr[rc].gg^=1;
tr[now].gg=false;
}
void bt(int l,int r)
{
trlen++; int now=trlen;
tr[now].l=l,tr[now].r=r;
tr[now].lc=tr[now].rc=-1;
tr[now].mx=tr[now].mn=tr[now].sum=0;
tr[now].gg=false;
if(l<r)
{
int mid=(l+r)/2;
tr[now].lc=trlen+1; bt(l,mid);
tr[now].rc=trlen+1; bt(mid+1,r);
}
}
void change(int now,int x,int c)
{
if(tr[now].l==tr[now].r)
{
tr[now].mx=tr[now].mn=tr[now].sum=c;
return;
}
if(tr[now].gg) fz(now);
int lc=tr[now].lc,rc=tr[now].rc;
int mid=(tr[now].l+tr[now].r)/2;
if(x<=mid) {change(lc,x,c);}
else if(mid+1<=x){ change(rc,x,c);}
tr[now].mx=max(tr[lc].mx,tr[rc].mx);
tr[now].mn=min(tr[lc].mn,tr[rc].mn);
tr[now].sum=tr[lc].sum+tr[rc].sum;
}
void change_fz(int now,int l,int r)
{
if(tr[now].l==l && tr[now].r==r)
{
tr[now].gg^=1;
swap(tr[now].mx,tr[now].mn);
tr[now].mx*=-1;
tr[now].mn*=-1;
tr[now].sum*=-1;
return;
}
if(tr[now].gg) fz(now);
int lc=tr[now].lc,rc=tr[now].rc;
int mid=(tr[now].l+tr[now].r)/2;
if(r<=mid) {change_fz(lc,l,r);}
else if(mid+1<=l){ change_fz(rc,l,r);}
else{
change_fz(lc,l,mid);
change_fz(rc,mid+1,r);
}
tr[now].mx=max(tr[lc].mx,tr[rc].mx);
tr[now].mn=min(tr[lc].mn,tr[rc].mn);
tr[now].sum=tr[lc].sum+tr[rc].sum;
}
int findmax(int now,int l,int r)
{
if(tr[now].l==l && tr[now].r==r){ return tr[now].mx;}
if(tr[now].gg) fz(now);
int lc=tr[now].lc,rc=tr[now].rc;
int mid=(tr[now].l+tr[now].r)/2;
if(r<=mid) return findmax(lc,l,r);
else if(mid+1<=l) return findmax(rc,l,r);
else return max(findmax(lc,l,mid),findmax(rc,mid+1,r));
}
int findmin(int now,int l,int r)
{
if(tr[now].l==l && tr[now].r==r){ return tr[now].mn;}
if(tr[now].gg) fz(now);
int lc=tr[now].lc,rc=tr[now].rc;
int mid=(tr[now].l+tr[now].r)/2;
if(r<=mid) return findmin(lc,l,r);
else if(mid+1<=l) return findmin(rc,l,r);
else return min(findmin(lc,l,mid),findmin(rc,mid+1,r));
}
int findsum(int now,int l,int r)
{
if(tr[now].l==l && tr[now].r==r){ return tr[now].sum;}
if(tr[now].gg) fz(now);
int lc=tr[now].lc,rc=tr[now].rc;
int mid=(tr[now].l+tr[now].r)/2;
if(r<=mid) return findsum(lc,l,r);
else if(mid+1<=l) return findsum(rc,l,r);
else return findsum(lc,l,mid)+findsum(rc,mid+1,r);
}
int solve_max(int x,int y)
{
int tx=top[x],ty=top[y];
int ans=-99999999;
while(tx!=ty)
{
if(dep[tx]>dep[ty])
{
swap(x,y);
swap(tx,ty);
}
ans=max(ans,findmax(1,ys[ty],ys[y]));
y=fa[ty],ty=top[y];
}
if(x==y) return ans;
else
{
if(dep[x]>dep[y]) swap(x,y);
return max(ans,findmax(1,ys[son[x]],ys[y]));
}
}
int solve_min(int x,int y)
{
int tx=top[x],ty=top[y];
int ans=99999999;
while(tx!=ty)
{
if(dep[tx]>dep[ty])
{
swap(x,y);
swap(tx,ty);
}
ans=min(ans,findmin(1,ys[ty],ys[y]));
y=fa[ty],ty=top[y];
}
if(x==y) return ans;
else
{
if(dep[x]>dep[y]) swap(x,y);
return min(ans,findmin(1,ys[son[x]],ys[y]));
}
}
int solve_sum(int x,int y)
{
int tx=top[x],ty=top[y];
int ans=0;
while(tx!=ty)
{
if(dep[tx]>dep[ty])
{
swap(x,y);
swap(tx,ty);
}
ans+=findsum(1,ys[ty],ys[y]);
y=fa[ty],ty=top[y];
}
if(x==y) return ans;
else
{
if(dep[x]>dep[y]) swap(x,y);
ans+=findsum(1,ys[son[x]],ys[y]);
return ans;
}
}
void solve_fz(int x,int y)
{
int tx=top[x],ty=top[y];
while(tx!=ty)
{
if(dep[tx]>dep[ty])
{
swap(x,y);
swap(tx,ty);
}
change_fz(1,ys[ty],ys[y]);
y=fa[ty],ty=top[y];
}
if(x==y) return ;
else
{
if(dep[x]>dep[y]) swap(x,y);
change_fz(1,ys[son[x]],ys[y]);
}
}
int main()
{
// freopen("travel.in","r",stdin);
// freopen("travel.out","w",stdout);
int n;scanf("%d",&n);
len=0;memset(last,0,sizeof(last));
for(int i=1;i<n;i++)
{
int x,y,c;
scanf("%d%d%d",&x,&y,&c);x++;y++;
ins(x,y,c);
ins(y,x,c);
}
fa[1]=0;dep[1]=1;
pre_tree_node(1);
z=0; pre_tree_edge(1,1);
trlen=0; bt(1,z);
for(int i=1;i<=len;i+=2)
{
int x=a[i].x,y=a[i].y,c=a[i].c,id;
if(dep[x]>dep[y]) id=x;
else id=y;
change(1,ys[id],c);
}
int m;scanf("%d",&m);
for(int i=1;i<=m;i++)
{
char ss[10]; scanf("%s",ss+1);
int u,v;scanf("%d%d",&u,&v);
if(ss[1]=='C')
{
int x=a[u*2-1].x,y=a[u*2-1].y,id;
if(dep[x]>dep[y]) id=x;
else id=y;
change(1,ys[id],v);
}
else if(ss[1]=='N') {u++,v++;solve_fz(u,v);}
else if(ss[1]=='S') {u++,v++;printf("%d\n",solve_sum(u,v));}
else if(ss[2]=='A') {u++,v++;printf("%d\n",solve_max(u,v));}
else if(ss[2]=='I') {u++,v++;printf("%d\n",solve_min(u,v));}
}
return 0;
}