传送门:BZOJ1036-树的统计
题意
一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w。我们将以下面的形式来要求你对这棵树完成
一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 I
II. QSUM u v: 询问从点u到点v的路径上的节点的权值和 注意:从点u到点v的路径上的节点包括u和v本身
输入
输入的第一行为一个整数n,表示节点的个数。接下来n – 1行,每行2个整数a和b,表示节点a和节点b之间有
一条边相连。接下来n行,每行一个整数,第i行的整数wi表示节点i的权值。接下来1行,为一个整数q,表示操作
的总数。接下来q行,每行一个操作,以“CHANGE u t”或者“QMAX u v”或者“QSUM u v”的形式给出。
对于100%的数据,保证1<=n<=30000,0<=q<=200000;中途操作中保证每个节点的权值w在-30000到30000之间。
题解
树链剖分+线段树水题,dfs序
代码
#include<bits/stdc++.h>
using namespace std;
const int N=3e4+10;
typedef long long ll;
int n,m,T,df[N],cnt;
ll mx[N<<4],sum[N<<4],v[N],ret,ss;
int head[N],to[N<<1],nxt[N<<1],tag[N],tot;
int son[N],f[N],sz[N],d[N],top[N];
char st[10];
inline int read()
{
char ch=getchar();int x=0,f=1;
while(ch<'0' || ch>'9'){if(ch=='-') f=-1;ch=getchar();}
while(ch>='0' && ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
return x*f;
}
inline void lk(int u,int v){
to[++tot]=v;nxt[tot]=head[u];head[u]=tot;
to[++tot]=u;nxt[tot]=head[v];head[v]=tot;
}
inline void swa(int &x,int &y){int t=x;x=y;y=t;}
inline int min(int x,int y){return x<y?x:y;}
inline ll max(ll x,ll y){return x>y?x:y;}
inline void update(int k)
{
sum[k]=sum[k<<1]+sum[k<<1|1];
mx[k]=max(mx[k<<1],mx[k<<1|1]);
}
inline void dfs(int x,int fa,int depth)
{
f[x]=fa;d[x]=depth;sz[x]=1;
for(int i=head[x];i;i=nxt[i]){
if(to[i]==fa) continue;
dfs(to[i],x,depth+1);
sz[x]+=sz[to[i]];
if(son[x]==0 || sz[son[x]]<sz[to[i]]) son[x]=to[i];
}
}
inline void dfb(int x,int tp)
{
top[x]=tp;df[x]=++cnt;
if(son[x]==0) return;
dfb(son[x],tp);
for(int i=head[x];i;i=nxt[i]){
if(to[i]==f[x] || to[i]==son[x]) continue;
dfb(to[i],to[i]);
}
}
inline void build(int k,int l,int r)
{
if(l==r){sum[k]=mx[k]=v[tag[l]];return;}
int mid=(l+r)>>1;
build(k<<1,l,mid);build(k<<1|1,mid+1,r);
update(k);
}
inline void change(int k,int l,int r,int pos,int val)
{
if(l==r){mx[k]=sum[k]=val;return;}
int mid=(l+r)>>1;
if(pos<=mid) change(k<<1,l,mid,pos,val);
else change(k<<1|1,mid+1,r,pos,val);
update(k);
}
inline void getmax(int k,int l,int r,int L,int R)
{
if(l>=L && r<=R){ret=max(ret,mx[k]);return;}
int mid=(l+r)>>1;
if(L<=mid) getmax(k<<1,l,mid,L,R);
if(R>mid) getmax(k<<1|1,mid+1,r,L,R);
}
inline void askmax(int x,int y)
{
ret=-30001;
while(top[x]!=top[y]){
if(d[top[x]]<d[top[y]]) swa(x,y);
getmax(1,1,n,df[top[x]],df[x]);
x=f[top[x]];
}
if(d[x]<d[y]) swa(x,y);
getmax(1,1,n,df[y],df[x]);
printf("%lld\n",ret);
}
inline void getsum(int k,int l,int r,int L,int R)
{
if(l>=L && r<=R){ss+=sum[k];return;}
int mid=(l+r)>>1;
if(L<=mid) getsum(k<<1,l,mid,L,R);
if(R>mid) getsum(k<<1|1,mid+1,r,L,R);
}
inline void asksum(int x,int y)
{
ss=0;
while(top[x]!=top[y]){
if(d[top[x]]<d[top[y]]) swa(x,y);
getsum(1,1,n,df[top[x]],df[x]);
x=f[top[x]];
}
if(d[x]<d[y]) swa(x,y);
getsum(1,1,n,df[y],df[x]);
printf("%lld\n",ss);
}
int main(){
int i,j,u,x,y;
n=read();
for(i=1;i<n;i++){u=read();lk(u,read());}
for(i=1;i<=n;i++) v[i]=read();
dfs(1,0,0);dfb(1,1);
for(i=1;i<=n;i++) tag[df[i]]=i;
build(1,1,n);
T=read();
while(T--){
scanf("%s",st);
x=read(),y=read();
if(st[0]=='C') change(1,1,n,df[x],y);
else if(st[1]=='M') askmax(x,y);
else asksum(x,y);
}
return 0;
}