P2590 [ZJOI2008]树的统计(树链剖分)

P2590 [ZJOI2008]树的统计

虽然是入门树剖模板

但是我终于1A了(大哭)

懒得写啥了(逃

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
inline int Max(int a,int b){return a>b?a:b;}
inline void Swap(int &a,int &b){a^=b^=a^=b;}
#define N 30005
int n,Q,Top[N],bgs[N],siz[N],fa[N],val[N];
int ID,id[N],tmp[N],sum[N<<],mxd[N<<];
int cnt,hd[N],nxt[N<<],ed[N],poi[N<<];
#define lc o<<1
#define rc o<<1|1
#define mid (l+r)/2
inline void adde(int x,int y){
nxt[ed[x]]=++cnt; hd[x]=hd[x]?hd[x]:cnt;
ed[x]=cnt; poi[cnt]=y;
}
inline void up(int o){
sum[o]=sum[lc]+sum[rc];
mxd[o]=Max(mxd[lc],mxd[rc]);
}
void build(int o,int l,int r){
if(l==r){sum[o]=mxd[o]=tmp[l]; return ;}
build(lc,l,mid); build(rc,mid+,r); up(o);
}
void modi(int o,int l,int r,int x,int v){
if(l==r){sum[o]=mxd[o]=v; return ;}
if(x<=mid) modi(lc,l,mid,x,v);
else modi(rc,mid+,r,x,v);
up(o);
}
int ask1(int o,int l,int r,int x1,int x2){
if(x1<=l&&r<=x2) return mxd[o];
int re=-1e9;
if(x1<=mid) re=Max(re,ask1(lc,l,mid,x1,x2));
if(x2>mid) re=Max(re,ask1(rc,mid+,r,x1,x2));
return re;
}
int ask2(int o,int l,int r,int x1,int x2){
if(x1<=l&&r<=x2) return sum[o];
int re=;
if(x1<=mid) re+=ask2(lc,l,mid,x1,x2);
if(x2>mid) re+=ask2(rc,mid+,r,x1,x2);
return re;
}
void dfs1(int x,int Fa){
fa[x]=Fa; siz[x]=;
for(int i=hd[x];i;i=nxt[i]){
int to=poi[i];
if(to==Fa) continue;
dfs1(to,x);
if(siz[to]>siz[bgs[x]]) bgs[x]=to;
siz[x]+=siz[to];
}
}
void dfs2(int x,int tp){
tmp[id[x]=++ID]=val[x]; Top[x]=tp;
if(bgs[x]) dfs2(bgs[x],tp);
for(int i=hd[x];i;i=nxt[i]){
int to=poi[i];
if(to==fa[x]||to==bgs[x]) continue;
dfs2(to,to);
}
}
int Amax(int x,int y){
int re=-1e9;
for(;Top[x]!=Top[y];x=fa[Top[x]]){
if(id[Top[x]]<id[Top[y]]) Swap(x,y);
re=Max(re,ask1(,,n,id[Top[x]],id[x]));
}if(id[x]>id[y]) Swap(x,y);
return Max(re,ask1(,,n,id[x],id[y]));
}
int Asum(int x,int y){
int re=;
for(;Top[x]!=Top[y];x=fa[Top[x]]){
if(id[Top[x]]<id[Top[y]]) Swap(x,y);
re+=ask2(,,n,id[Top[x]],id[x]);
}if(id[x]>id[y]) Swap(x,y);
return re+ask2(,,n,id[x],id[y]);
}
int main(){
scanf("%d",&n); int q1,q2; char opt[];
for(int i=;i<n;++i)
scanf("%d%d",&q1,&q2),adde(q1,q2),adde(q2,q1);
for(int i=;i<=n;++i) scanf("%d",&val[i]);
dfs1(,); dfs2(,);build(,,n);
scanf("%d",&Q);
while(Q--){
scanf("%s%d%d",opt,&q1,&q2);
if(opt[]=='H') modi(,,n,id[q1],q2);
else if(opt[]=='M') printf("%d\n",Amax(q1,q2));
else if(opt[]=='S') printf("%d\n",Asum(q1,q2));
}return ;
}
上一篇:Linux主机共享目录给Windows主机的方法


下一篇:vmware linux 虚拟机开机状态加硬盘