比较麻烦的树链剖分,其中Neg表示a、b之间所有数取相反数,可以用lazy标记处理,由于代码量略大注意别手残。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#define maxn 100005
#define inf 0x3fffffff
using namespace std;
int dep[maxn],top[maxn],id[maxn],son[maxn],size[maxn],num,fa[maxn],tot,head[maxn];
struct pppi{
int to;
int next;
}pp2[2*maxn];
struct ppi{
int f;
int t;
int co;
}pp1[maxn];
struct pi{
int le;
int ri;
int lazy;
int max;
int min;
}pp[4*maxn];
void add(int u,int v){
pp2[tot].to=v;
pp2[tot].next=head[u];
head[u]=tot++;
pp2[tot].to=u;
pp2[tot].next=head[v];
head[v]=tot++;
}
void build(int tot,int l,int r){
pp[tot].le=l;
pp[tot].ri=r;
pp[tot].lazy=0;
pp[tot].max=-inf;
pp[tot].min=inf;
if(l==r) return ;
build(2*tot,l,(l+r)/2);
build(2*tot+1,(l+r)/2+1,r);
}
int q1(int tot,int l,int r){
if(pp[tot].le>=l&&pp[tot].ri<=r) return pp[tot].lazy;
int s=0;
s+=pp[tot].lazy;
int mid=(pp[tot].le+pp[tot].ri)/2;
if(l<=mid) s+=q1(2*tot,l,r);
if(r>mid) s+=q1(2*tot+1,l,r);
return s;
}
void push(int tot){
int x1,y1,x2,y2;
if(pp[2*tot].lazy%2==0){ x1=pp[2*tot].max;
x2=pp[2*tot].min;
}
else{
x1=-pp[2*tot].min;
x2=-pp[2*tot].max;
}
if(pp[2*tot+1].lazy%2==0){
y1=pp[2*tot+1].max;
y2=pp[2*tot+1].min;
}
else{
y1=-pp[2*tot+1].min;
y2=-pp[2*tot+1].max;
}
pp[tot].max=max(x1,y1);
pp[tot].min=min(x2,y2);
}
void merg(int tot,int x,int p){
if(pp[tot].le==pp[tot].ri){
pp[tot].max=p;
pp[tot].min=p;
return ;
}
int mid=(pp[tot].le+pp[tot].ri)/2;
if(x<=mid) merg(2*tot,x,p);
else merg(2*tot+1,x,p);
push(tot);
}
void merg1(int tot,int l,int r){
if(pp[tot].le>=l&&pp[tot].ri<=r){
pp[tot].lazy++;
return ;
}
int mid=(pp[tot].le+pp[tot].ri)/2;
if(l<=mid) merg1(2*tot,l,r);
if(r>mid) merg1(2*tot+1,l,r);
push(tot);
}
int query(int tot,int l,int r){
if(pp[tot].le>=l&&pp[tot].ri<=r){
if(q1(1,pp[tot].le,pp[tot].ri)%2==0)
return pp[tot].max;
return -pp[tot].min;
}
int s=-inf,mid=(pp[tot].le+pp[tot].ri)/2;
if(l<=mid) s=max(s,query(2*tot,l,r));
if(r>mid) s=max(s,query(2*tot+1,l,r));
return s;
}
void dfs1(int u,int pa,int d){
dep[u]=d;
size[u]=1;
son[u]=0;
fa[u]=pa;
int k,v;
k=head[u];
while(k!=-1){
v=pp2[k].to;
if(v!=pa){
dfs1(v,u,d+1);
size[u]+=size[v];
if(size[son[u]]<size[v]) son[u]=v;
}
k=pp2[k].next;
}
}
void dfs2(int u,int pa,int tp){
top[u]=tp;
id[u]=num++;
if(son[u]) dfs2(son[u],u,tp);
int k,v;
k=head[u];
while(k!=-1){
v=pp2[k].to;
if(v!=pa&&v!=son[u]){
dfs2(v,u,v);
}
k=pp2[k].next;
}
}
void update(int u,int v){
int to1,to2;
to1=top[u];
to2=top[v];
while(to1!=to2){
if(dep[to1]<dep[to2]||(dep[to1]==dep[to2]&&u<v)){
swap(to1,to2);
swap(u,v);
}
if(!(u==to1&&u==1))
merg1(1,id[to1],id[u]);
u=fa[to1];
to1=top[u];
}
if(u==v) return ;
if(dep[u]>dep[v]) swap(u,v);
merg1(1,id[u]+1,id[v]);
}
int get(int u,int v){
int to1,to2,s;
s=-inf;
to1=top[u];
to2=top[v];
while(to1!=to2){
if(dep[to1]<dep[to2]){
swap(to1,to2);
swap(u,v);
}
s=max(s,query(1,id[to1],id[u]));
u=fa[to1];
to1=top[u];
}
if(u==v) return s;
if(dep[u]>dep[v]) swap(u,v);
s=max(s,query(1,id[u]+1,id[v]));
return s;
}
char c[20];
int main()
{
int t,n,i,p,k;
cin>>t;
while(t--){
scanf("%d",&n);
memset(head,-1,sizeof(head));
tot=0;
num=0;
build(1,1,n-1);
for(i=1;i<n;i++){
scanf("%d%d%d",&pp1[i].f,&pp1[i].t,&pp1[i].co);
add(pp1[i].f,pp1[i].t);
}
dfs1(1,1,1);
dfs2(1,1,1);
for(i=1;i<n;i++){
if(fa[pp1[i].t]==pp1[i].f) merg(1,id[pp1[i].t],pp1[i].co);
else merg(1,id[pp1[i].f],pp1[i].co);
}
while(1){
scanf("%s",c);
if(c[0]=='D') break;
if(c[0]=='Q'){
scanf("%d%d",&p,&k);
if(p==k){
printf("0\n");
continue;
}
printf("%d\n",get(p,k));
}
else if(c[0]=='C'){
scanf("%d%d",&p,&k);
if(fa[pp1[p].f]==pp1[p].t){
if(q1(1,id[pp1[p].f],id[pp1[p].f])%2==0)
merg(1,id[pp1[p].f],k);
else merg(1,id[pp1[p].f],-k);
}
else{
if(q1(1,id[pp1[p].t],id[pp1[p].t])%2==0)
merg(1,id[pp1[p].t],k);
else merg(1,id[pp1[p].t],-k);
}
}
else if(c[0]=='N'){
scanf("%d%d",&p,&k);
update(p,k);
}
}
}
}

本文介绍了一种复杂的树链剖分算法,该算法利用Lazy标记来处理区间内数值的相反数操作。通过详细展示代码实现过程,帮助读者理解树链剖分的基本原理及其实现细节。
391

被折叠的 条评论
为什么被折叠?



