这道题算是树链剖分的模板题吧(其实也是我过的第一道树链剖分的题目)。历尽千辛万苦,终于把两百多行的代码敲出来了,ac的一瞬间还是挺爽的。
在学会了树链剖分之后,这道题不算很难的了,主要是在区间取反的部分注意一下细节。树链剖分代码挺长的,很多地方都是容易写错。我也是通过讨论区的acmer给出的数据找出一些错误的地方。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<set>
#include<vector>
#include<map>
#include<queue>
#include<climits>
#include<assert.h>
using namespace std;
//树链剖分
const int maxn = 10005;
int dep[maxn],siz[maxn],fa[maxn],id[maxn],son[maxn],num[maxn],top[maxn];
int fir[maxn],vv[maxn<<1],val[maxn<<1],nxt[maxn<<1],e;
int ll[maxn<<2],rr[maxn<<2],maxed[maxn<<2],minn[maxn<<2];
bool negative[maxn<<2];
int idx;
struct Edge
{
int from,to,val;
Edge(int f,int t,int v)
:from(f),to(t),val(v){}
Edge(){}
};
vector<Edge>vec;
void add(int a,int b,int v)
{
vv[e]=b;
val[e]=v;
nxt[e]=fir[a];
fir[a]=e++;
}
void dfs(int cur,int pre)
{
siz[cur]=1;son[cur]=-1;
int maxed=-1,sonn=-1;
for(int i=fir[cur];i!=-1;i=nxt[i])
{
int v=vv[i];
if(v==pre) continue;
dep[v]=dep[cur]+1;
fa[v]=cur;
dfs(v,cur);
if(siz[v]>maxed)
{
maxed=siz[v];
sonn=v;
}
siz[cur]+=siz[v];
}
son[cur]=sonn;
}
void dfs2(int cur,int tp)
{
top[cur]=tp;
id[cur]=++idx;
if(son[cur]!=-1) dfs2(son[cur],tp);
for(int i=fir[cur];i!=-1;i=nxt[i])
{
int v=vv[i];
if(v==fa[cur]||v==son[cur]) continue;
dfs2(v,v);
}
}
void push_down(int i)
{
if(negative[i])
{
int ls=i<<1,rs=ls|1;
negative[ls]=!negative[ls];
negative[rs]=!negative[rs];
int temp=maxed[ls];//要用中间变量记录
maxed[ls]=-minn[ls];
minn[ls]=-temp;
temp=maxed[rs];
maxed[rs]=-minn[rs];
minn[rs]=-temp;
negative[i]=false;
}
}
void build(int i,int l,int r)
{
ll[i]=l,rr[i]=r,negative[i]=false;
if(l==r)
{
maxed[i]=num[l];
minn[i]=num[l];
return ;
}
int mid=(l+r)>>1,ls=i<<1,rs=ls|1;
build(ls,l,mid);
build(rs,mid+1,r);
maxed[i]=max(maxed[ls],maxed[rs]);
minn[i]=min(minn[ls],minn[rs]);
}
void updatePos(int i,int pos,int _val)
{
if(ll[i]==rr[i])
{
maxed[i]=_val;
minn[i]=_val;
return;
}
push_down(i);//不能漏掉这一句
int mid=(ll[i]+rr[i])>>1,ls=i<<1,rs=ls|1;
if(pos<=mid) updatePos(ls,pos,_val);
else updatePos(rs,pos,_val);
maxed[i]=max(maxed[ls],maxed[rs]);
minn[i]=min(minn[ls],minn[rs]);
}
void negaSeg(int i,int l,int r)
{
if(ll[i]>=l&&rr[i]<=r)
{
negative[i]=!negative[i];
int temp=minn[i];
minn[i]=-maxed[i];
maxed[i]=-temp;
return;
}
push_down(i);
int mid=(ll[i]+rr[i])>>1,ls=i<<1,rs=ls|1;
if(l>mid) negaSeg(rs,l,r);
else if(r<=mid) negaSeg(ls,l,r);
else
{
negaSeg(ls,l,r);
negaSeg(rs,l,r);
}
maxed[i]=max(maxed[ls],maxed[rs]);
minn[i]=min(minn[ls],minn[rs]);
}
int query_max(int i,int l,int r)
{
if(ll[i]>=l&&rr[i]<=r)
return maxed[i];
push_down(i);
int mid=(ll[i]+rr[i])>>1,ls=i<<1,rs=ls|1;
if(l>mid) return query_max(rs,l,r);
else if(r<=mid) return query_max(ls,l,r);
else return max(query_max(ls,l,r),query_max(rs,l,r));
}
int query_min(int i,int l,int r)
{
if(ll[i]>=l&&rr[i]<=r)
return minn[i];
push_down(i);
int mid=(ll[i]+rr[i])>>1,ls=i<<1,rs=ls|1;
if(l>mid) return query_min(rs,l,r);
else if(r<=mid) return query_min(ls,l,r);
else return min(query_min(ls,l,r),query_min(rs,l,r));
}
//initialize the upper edge of one node
void init()
{
for(int i=0;i<vec.size();i++)
{
Edge cur=vec[i];
int high=cur.from,low=cur.to;
if(dep[high]<dep[low]) swap(high,low);
num[id[high]]=cur.val;
}
}
int query_tree(int u,int v)
{
int tp1=top[u],tp2=top[v];
int ans=-(INT_MAX/2);
while(tp1!=tp2)
{
if(dep[tp1]<dep[tp2])
{
swap(tp1,tp2);
swap(u,v);
}
ans=max(query_max(1,id[tp1],id[u]),ans);
u=fa[tp1];
tp1=top[u];
}
if(u==v) return ans;
if(dep[u]>dep[v]) swap(u,v);
ans=max(ans,query_max(1,id[son[u]],id[v]));
return ans;
}
void nega_tree(int u,int v)
{
int tp1=top[u],tp2=top[v];
while(tp1!=tp2)
{
if(dep[tp1]<dep[tp2])
{
swap(tp1,tp2);
swap(u,v);
}
negaSeg(1,id[tp1],id[u]);
u=fa[tp1];tp1=top[u];
}
if(u==v) return;
if(dep[u]>dep[v]) swap(u,v);
negaSeg(1,id[son[u]],id[v]);
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)fir[i]=-1,num[i]=0;
e=0;idx=0;
vec.clear();
int a,b,v;
for(int i=1;i<n;i++)
{
scanf("%d%d%d",&a,&b,&v);
add(a,b,v);
add(b,a,v);
vec.push_back(Edge(a,b,v));//这一句不能在add函数里面写
}
dep[1]=0;
dfs(1,1);
dfs2(1,1);
init();
build(1,1,n);
char ins[10];
while(scanf("%s",ins)!=EOF)
{
if(ins[0]=='D') break;
if(ins[0]=='C')
{
scanf("%d%d",&a,&b);
Edge cur=vec[a-1];
int from=cur.from,to=cur.to;
if(dep[from]<dep[to]) swap(from,to);
updatePos(1,id[from],b);
}
else if(ins[0]=='N')
{
scanf("%d%d",&a,&b);
nega_tree(a,b);
}
else if(ins[0]=='Q')
{
scanf("%d%d",&a,&b);
printf("%d\n",query_tree(a,b));
}
}
}
}
/*
1000
6
1 2 1
2 3 2
3 4 4
4 5 100
5 6 -1000
CHANGE 2 20
QUERY 1 3
NEGATE 1 2
QUERY 1 3
*/