# 【POJ3237】Tree（树链剖分）

1097 篇文章 2 订阅
23 篇文章 0 订阅
70 篇文章 0 订阅

## 题解

v的深度大于u），而如果u=v的话应该直接退出。

## 代码

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;

const int max_n=1e4+5;
const int max_e=max_n*2;
const int mininf=-2100000000;
const int max_N=max_n*4;

int T,n,x,y,z,N,u,t,ans;
int tot,next[max_e],point[max_n],v[max_e],c[max_e];
int size[max_n],h[max_n],father[max_n],son[max_n],top[max_n];
int sonedge[max_n],faedge[max_n],num[max_e],val[max_e];
int maxn[max_N],minn[max_N],delta[max_N];
char s[10];

inline void clear(){
memset(next,0,sizeof(next));
memset(point,0,sizeof(point));
memset(v,0,sizeof(v));
memset(c,0,sizeof(c));
memset(size,0,sizeof(size));
memset(h,0,sizeof(h));
memset(father,0,sizeof(father));
memset(son,0,sizeof(son));
memset(sonedge,0,sizeof(sonedge));
memset(faedge,0,sizeof(faedge));
memset(top,0,sizeof(top));
memset(num,0,sizeof(num));
memset(val,0,sizeof(val));
memset(maxn,0,sizeof(maxn));
memset(minn,0,sizeof(minn));
memset(delta,0,sizeof(delta));
tot=0;
n=x=y=z=N=u=t=ans=0;
}

inline void add(int x,int y,int z){
++tot; next[tot]=point[x]; point[x]=tot; v[tot]=y; c[tot]=z;
++tot; next[tot]=point[y]; point[y]=tot; v[tot]=x; c[tot]=z;
}

inline void dfs_1(int x,int fa,int dep){
size[x]=1; h[x]=dep; father[x]=fa;
int maxson=0;
for (int i=point[x];i;i=next[i])
if (v[i]!=fa){
faedge[v[i]]=i;
dfs_1(v[i],x,dep+1);
size[x]+=size[v[i]];
if (maxson<size[v[i]]){
maxson=size[v[i]];
son[x]=v[i];
sonedge[x]=i;
}
}
}

inline void dfs_2(int x,int fa){
if (son[fa]!=x) top[x]=x;
else top[x]=top[fa];

for (int i=point[x];i;i=next[i])
if (v[i]==son[x]){
num[i]=++N;
val[N]=c[i];
dfs_2(son[x],x);
}

for (int i=point[x];i;i=next[i])
if (v[i]!=fa&&v[i]!=son[x]){
num[i]=++N;
val[N]=c[i];
dfs_2(v[i],x);
}
}

inline void update(int now){
maxn[now]=max(maxn[now<<1],maxn[now<<1|1]);
minn[now]=min(minn[now<<1],minn[now<<1|1]);
}

inline void pushdown(int now,int l,int r,int mid){
if (delta[now]%2){
swap(maxn[now<<1],minn[now<<1]);
maxn[now<<1]*=-1;
minn[now<<1]*=-1;
delta[now<<1]++;
swap(maxn[now<<1|1],minn[now<<1|1]);
maxn[now<<1|1]*=-1;
minn[now<<1|1]*=-1;
delta[now<<1|1]++;
}
delta[now]=0;
}

inline void build(int now,int l,int r){
int mid=(l+r)>>1;
if (l==r){
maxn[now]=val[l];
minn[now]=val[l];
return;
}
build(now<<1,l,mid);
build(now<<1|1,mid+1,r);
update(now);
}

inline void point_change(int now,int l,int r,int x,int v){
int mid=(l+r)>>1;
if (l==r){
maxn[now]=v;
minn[now]=v;
return;
}
pushdown(now,l,r,mid);
if (x<=mid)
point_change(now<<1,l,mid,x,v);
else
point_change(now<<1|1,mid+1,r,x,v);
update(now);
}

inline void interval_change(int now,int l,int r,int lrange,int rrange){
int mid=(l+r)>>1;
if (lrange<=l&&r<=rrange){
swap(maxn[now],minn[now]);
maxn[now]*=-1;
minn[now]*=-1;
delta[now]++;
return;
}
pushdown(now,l,r,mid);
if (lrange<=mid)
interval_change(now<<1,l,mid,lrange,rrange);
if (mid+1<=rrange)
interval_change(now<<1|1,mid+1,r,lrange,rrange);
update(now);
}

inline int query(int now,int l,int r,int lrange,int rrange){
int mid=(l+r)>>1,ans=mininf;
if (lrange<=l&&r<=rrange) return maxn[now];
pushdown(now,l,r,mid);
if (lrange<=mid)
ans=max(ans,query(now<<1,l,mid,lrange,rrange));
if (mid+1<=rrange)
ans=max(ans,query(now<<1|1,mid+1,r,lrange,rrange));
return ans;
}

inline void NEGATE(int u,int t){
int f1=top[u],f2=top[t];
while (f1!=f2){
if (h[f1]<h[f2]){
swap(u,t);
swap(f1,f2);
}
interval_change(1,1,N,num[faedge[f1]],num[faedge[u]]);
u=father[f1];
f1=top[u];
}
if (u==t) return;
if (h[u]>h[t]) swap(u,t);
interval_change(1,1,N,num[sonedge[u]],num[faedge[t]]);
}

inline int QUERY(int u,int t){
int ans=mininf;
int f1=top[u],f2=top[t];
while (f1!=f2){
if (h[f1]<h[f2]){
swap(u,t);
swap(f1,f2);
}
ans=max(ans,query(1,1,N,num[faedge[f1]],num[faedge[u]]));
u=father[f1];
f1=top[u];
}
if (u==t) return ans;
if (h[u]>h[t]) swap(u,t);
ans=max(ans,query(1,1,N,num[sonedge[u]],num[faedge[t]]));
return ans;
}

int main(){
scanf("%d",&T);
while (T--){
clear();

scanf("%d",&n);
for (int i=1;i<n;++i){
scanf("%d%d%d",&x,&y,&z);
}

dfs_1(1,0,1);

dfs_2(1,0);

build(1,1,N);
scanf("%s",s);
while (strlen(s)>4){
scanf("%d%d",&u,&t);
switch(s[0]){
case 'C':{
if (num[u*2-1]) x=num[u*2-1];
else x=num[u*2];
point_change(1,1,N,x,t);
break;
}
case 'N':{
NEGATE(u,t);
break;
}
case 'Q':{
ans=QUERY(u,t);
printf("%d\n",ans);
break;
}
}
scanf("%s",s);
}
}
}

## 总结

①线段树只要牵扯到区间修改，所有的操作之前都要pushdown，所有的修改操作之后都要update

• 1
点赞
• 0
收藏
觉得还不错? 一键收藏
• 打赏
• 0
评论
10-15 2171
07-14 390
01-23 1460
09-24 138
09-28 392
12-05
11-18
05-27
04-14
04-13
09-20
09-19

### “相关推荐”对你有帮助么？

• 非常没帮助
• 没帮助
• 一般
• 有帮助
• 非常有帮助

Clove_unique

¥2 ¥4 ¥6 ¥10 ¥20

1.余额是钱包充值的虚拟货币，按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载，可以购买VIP、C币套餐、付费专栏及课程。