题解:ZJOI2008 树的统计 【树链剖分】

这个题目就是树剖的板子题(比板子还裸)

于是就直接上了QAQ

还是先扯一下树剖吧

fa[x]:x在树中的父亲
dep[x]:x在树中的深度
size[x]:x的子树结点数(子树大小)
son[x]:x的重儿子,即u→son[u]为重边
top[x]:x所在重路径的顶部结点(深度最小)
seg[x]:x在线段树中的位置(下标) (但是我一直发疯打的seq)
rev[x]:线段树中第x个位置对应的树中结点编号,即rev[seg[x]]=x

对于前四个,我们一遍DFS即可,后三个数组我们再用一遍DFS也求了出来
于是就可以欢快的套上线段树维护了

其实树剖码量挺大的
当年弱,调程序调到死

丑陋的代码:

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
#define FOR(i,n,m) for(int i=n;i<=m;++i)
#define FR(i,n,m) for(int i=n;i>=m;--i)
#define max(a,b) (a>b?a:b)
#define min(a,b) (a<b?a:b)
#define re register
#define gc getchar()
using namespace std;
const int N=100010,INF=2139062143;
inline int read() {
    re int x(0),f(1);
    re char ch=gc;
    while(ch<'0'||ch>'9') {
        if(ch=='-') f=-1;
        ch=gc;
    }
    while(ch>='0'&&ch<='9') {
        x=(x<<1)+(x<<3)+(ch^48);
        ch=gc;
    }
    return x*f;
}

int size[N],fa[N],deep[N],son[N];
struct edge {
    int next,to;
}e[N];
int h[N],cnt;
inline void add(int u,int v) {
    e[++cnt]=(edge) {h[u],v};
    h[u]=cnt;
}
#define QXX(u) for(int v,i=h[u];v=e[i].to,i;i=e[i].next)

bool vis[N];
void dfs1(int now) {
    vis[now]=1;
    size[now]=1;
    QXX(now) if(v!=fa[now]&&!vis[v]) {
        deep[v]=deep[now]+1;
        fa[v]=now;
        dfs1(v);
        size[now]+=size[v];
        if(size[v]>size[son[now]]) son[now]=v;
    }
}
int seq[N],rev[N],top[N];
void dfs2(int now) {
    if(son[now]) {
        top[son[now]]=top[now];
        seq[son[now]]=++seq[0];
        rev[seq[0]]=son[now];
        dfs2(son[now]);
    }
    QXX(now) if(!top[v]) {
        if(v!=son[now]) {
            top[v]=v;
            seq[v]=++seq[0];
            rev[seq[0]]=v;
            dfs2(v);
        }
    }
}
struct node {
    int _max,sum;
}a[N];
#define ls id<<1
#define rs id<<1|1
int num[N];

inline void update(int id) {
    a[id].sum=a[ls].sum+a[rs].sum;
    a[id]._max=max(a[ls]._max,a[rs]._max);
}
inline void built(int l,int r,int id) {
    if(l==r) {
        a[id]._max=a[id].sum=num[rev[l]];
        return;
    }
    int mid=(l+r)>>1;
    built(l,mid,ls);
    built(mid+1,r,rs);
    update(id);
}
inline void revise(int id,int l,int r,int k,int val) {
    if(l>k||r<k) return;
    if(l==r&&l==k) {
        a[id].sum=val;
        a[id]._max=val;
        return;
    }
    int mid=(l+r)>>1; 
    if(mid>=k) revise(ls,l,mid,k,val);
    else revise(rs,mid+1,r,k,val);
    update(id);
}
int sum,_max;
inline void query(int id,int l,int r,int x,int y) {
    if(x>r||y<l) return;
    if(l>=x&&r<=y) {
        sum+=a[id].sum;
        _max=max(_max,a[id]._max);
        return;
    }
    int mid=(l+r)>>1;
    if(mid>=x) query(ls,l,mid,x,y);
    if(mid<y) query(rs,mid+1,r,x,y);
}
inline void ask(int x,int y) {
    int tx=top[x],ty=top[y];
    while(tx!=ty) {
        if(deep[tx]<deep[ty]) swap(tx,ty),swap(x,y);
        query(1,1,seq[0],seq[tx],seq[x]);
        x=fa[tx],tx=top[x];
    }
    if(deep[x]>deep[y]) swap(x,y);
    query(1,1,seq[0],seq[x],seq[y]);
}
int main() {
    int n=read();
    FOR(i,1,n-1) {
        int x=read(),y=read();
        add(x,y),add(y,x);
    }
    FOR(i,1,n) num[i]=read();
    dfs1(1);
    seq[0]=seq[1]=top[1]=rev[1]=1;
    dfs2(1);
    built(1,seq[0],1);
    
    int Q=read();
    while(Q--) {
        string ss;
        cin>>ss;
        if(ss[0]=='C') {
            int x=read(),y=read();
            revise(1,1,seq[0],seq[x],y);
        }
        else {
            int x=read(),y=read();
            _max=-0x3f3f3f3f,sum=0;
            ask(x,y);
            if(ss[1]=='S')  cout<<sum<<endl;
            else cout<<_max<<endl; 
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_43464026/article/details/88387315
今日推荐