洛谷2590 [ZJOI2008]树的统计

Luogu

分析

树剖板子。

线段树支持单点赋值、区间求和、区间最大值即可。

这个线段树还比较好写

代码

#include <bits/stdc++.h>
#define re register
using namespace std;

inline int read() {
    int X=0,w=1; char c=getchar();
    while (c<'0'||c>'9') { if (c=='-') w=-1; c=getchar(); }
    while (c>='0'&&c<='9') X=X*10+c-'0',c=getchar();
    return X*w;
}

const int MAXN=30010;
const int INF=2147483647;

struct Edge { int v,nxt; };
Edge e[MAXN<<1];
int head[MAXN],cnt=0;

inline void addEdge(int u,int v) {
    e[++cnt].v=v,e[cnt].nxt=head[u],head[u]=cnt;
}

int n;
int a[MAXN];
int real[MAXN],dep[MAXN],fa[MAXN],sz[MAXN],hson[MAXN],top[MAXN],id[MAXN];
int tot=0;

inline void Dfs1(int u,int f) {
    fa[u]=f,sz[u]=1;
    for (re int i=head[u];i;i=e[i].nxt) {
        int v=e[i].v;
        if (v==f) continue;
        dep[v]=dep[u]+1;
        Dfs1(v,u);
        sz[u]+=sz[v];
        if (!hson[u]||sz[v]>sz[hson[u]]) hson[u]=v;
    }
}

inline void Dfs2(int u,int anc) {
    top[u]=anc,id[u]=++tot,real[tot]=u;
    if (!hson[u]) return;
    Dfs2(hson[u],anc);
    for (re int i=head[u];i;i=e[i].nxt) {
        int v=e[i].v;
        if (v!=fa[u]&&v!=hson[u]) Dfs2(v,v);
    }
}

struct Segment_Tree {
    int sumv[MAXN<<2],maxv[MAXN<<2];
#define lson (o<<1)
#define rson (o<<1|1)
    inline void pushup(int o) {
        sumv[o]=sumv[lson]+sumv[rson];
        maxv[o]=max(maxv[lson],maxv[rson]);
    }
    inline void build(int o,int l,int r) {
        if (l==r) { sumv[o]=maxv[o]=a[real[l]]; return; }
        int mid=(l+r)>>1;
        build(lson,l,mid);
        build(rson,mid+1,r);
        pushup(o);
    }
    inline void update(int o,int l,int r,int p,int v) {
        if (l==r) { sumv[o]=maxv[o]=v; return; }
        int mid=(l+r)>>1;
        if (p<=mid) update(lson,l,mid,p,v);
        if (p>mid) update(rson,mid+1,r,p,v);
        pushup(o);
    }
    inline int querysum(int o,int l,int r,int ql,int qr) {
        if (ql<=l&&r<=qr) return sumv[o];
        int mid=(l+r)>>1,rt=0;
        if (ql<=mid) rt+=querysum(lson,l,mid,ql,qr);
        if (qr>mid) rt+=querysum(rson,mid+1,r,ql,qr);
        pushup(o);
        return rt;
    }
    inline int querymax(int o,int l,int r,int ql,int qr) {
        if (ql<=l&&r<=qr) return maxv[o];
        int mid=(l+r)>>1,rt=-INF;
        if (ql<=mid) rt=querymax(lson,l,mid,ql,qr);
        if (qr>mid) rt=max(rt,querymax(rson,mid+1,r,ql,qr));
        pushup(o);
        return rt;
    }
#undef lson
#undef rson
};

Segment_Tree T;

inline void change(int u,int v) { T.update(1,1,n,id[u],v); }
inline int qsum(int u,int v) {
    int tu=top[u],tv=top[v],ans=0;
    while (tu!=tv) {
        if (dep[tu]<dep[tv]) { swap(tu,tv); swap(u,v); }
        ans+=T.querysum(1,1,n,id[tu],id[u]);
        u=fa[tu],tu=top[u];
    }
    if (dep[u]<dep[v]) swap(u,v);
    ans+=T.querysum(1,1,n,id[v],id[u]);
    return ans;
}
inline int qmax(int u,int v) {
    int tu=top[u],tv=top[v],ans=-INF;
    while (tu!=tv) {
        if (dep[tu]<dep[tv]) { swap(tu,tv); swap(u,v); }
        ans=max(ans,T.querymax(1,1,n,id[tu],id[u]));
        u=fa[tu],tu=top[u];
    }
    if (dep[u]<dep[v]) swap(u,v);
    ans=max(ans,T.querymax(1,1,n,id[v],id[u]));
    return ans;
}

char tmp[20];

int main() {
    n=read();
    for (re int i=1,u,v;i<n;i++) {
        u=read(),v=read();
        addEdge(u,v); addEdge(v,u);
    }
    for (re int i=1;i<=n;i++) a[i]=read();
    dep[1]=1; Dfs1(1,0); Dfs2(1,1); T.build(1,1,n);
    int T=read();
    while (T--) {
        scanf("%s",tmp+1); char c=tmp[2];
        int x=read(),y=read();
        if (c=='H') change(x,y);
        else if (c=='S') printf("%d\n",qsum(x,y));
        else if (c=='M') printf("%d\n",qmax(x,y));
    }
    return 0;
}
最后修改:2019 年 09 月 24 日 01 : 30 PM

发表评论