P3979 遥远的国度 树剖

P3979 遥远的国度 树剖

题面

需要想一下的树剖题,对于询问三需要处理换跟后的情况。我们以1为树根跑一遍剖分,对于换跟进行分类讨论,算出实际答案。讨论有三种情况:

(以1为树根的树上)

  • 跟在询问节点的祖先上:因为不影响,所以直接求子树最小值

  • 跟即询问节点:直接查全树

  • 跟在询问节点子树中:画图容易得出,此时询问节点范围包含全树除了\(son\)的子树,其中\(son\)为跟向上跳达到询问节点的上一个节点。于是我们除去线段树区间\([idx[son], idx[son]+sz[son]-1]\)分左右区间讨论就好了。

#include <cstdio>
#include <algorithm>
#define MAXN 100010
#define ll long long
#define sl (x<<1)
#define sr (x<<1|1)
using namespace std;
int head[MAXN],vv[MAXN*2],nxt[MAXN*2],tot;
const int INF=0x3fffffff;
inline void add_edge(int u, int v){
    vv[++tot]=v;
    nxt[tot]=head[u];
    head[u]=tot;
}
int nod_val[MAXN];
int mxs[MAXN],sz[MAXN],dep[MAXN];
int f[MAXN][20];
void dfs1(int u, int fa){
    dep[u]=dep[fa]+1;
    f[u][0]=fa;
    for(int i=1;i<=17;++i)
        f[u][i]=f[f[u][i-1]][i-1];
    sz[u]=1;
    int mxsz=-1;
    for(int i=head[u];i;i=nxt[i]){
        int v=vv[i];
        if(v==fa) continue;
        dfs1(v, u);
        sz[u]+=sz[v];
        if(mxsz<sz[v]){
            mxsz=sz[v];
            mxs[u]=v;
        }
    }
}
int idx[MAXN],topf[MAXN],cnt,wnew[MAXN];
void dfs2(int u, int top){
    idx[u]=++cnt;
    topf[u]=top;
    wnew[cnt]=nod_val[u];
    if(mxs[u]==0) return;
    dfs2(mxs[u], top);
    for(int i=head[u];i;i=nxt[i]){
        int v=vv[i];
        if(v==f[u][0]||v==mxs[u]) continue;
        dfs2(v, v);
    }
}
struct nod{
    int l, r;
    int val,lazy;
} tre[MAXN*4];

void buildt(int x, int l, int r){
    tre[x].l=l,tre[x].r=r,tre[x].lazy=0;
    if(l==r){
        tre[x].val=wnew[l];
        return;
    }
    int mid=(l+r)>>1;
    buildt(sl, l, mid);
    buildt(sr, mid+1, r);
    tre[x].val=min(tre[sl].val, tre[sr].val);
}
void push_down(int x){
    if(tre[x].lazy==0) return;
    tre[sl].lazy=tre[sl].val=tre[x].lazy;
    tre[sr].lazy=tre[sr].val=tre[x].lazy;
    tre[x].lazy=0;
}
void change(int x, int l, int r, int val){
    if(l<=tre[x].l&&tre[x].r<=r){
        tre[x].lazy=tre[x].val=val;
        return;
    }
    push_down(x);
    int mid=(tre[x].l+tre[x].r)>>1;
    if(l<=mid) change(sl, l, r, val);
    if(mid<r) change(sr, l, r, val);
    tre[x].val=min(tre[sl].val, tre[sr].val);
}
int query(int x, int l, int r){
    if(l<=tre[x].l&&tre[x].r<=r){
        return tre[x].val;
    }
    push_down(x);
    int mid=(tre[x].l+tre[x].r)>>1;
    int ans=INF;
    if(l<=mid) ans=min(query(sl, l, r), ans);
    if(mid<r) ans=min(query(sr, l, r), ans);
    return ans;
}
void tre_change(int a, int b, int val){
    while(topf[a]!=topf[b]){
        if(dep[topf[a]]<dep[topf[b]]) swap(a,b);
        change(1, idx[topf[a]], idx[a], val);
        a=f[topf[a]][0];
    }
    if(dep[a]<dep[b]) swap(a,b);
    change(1, idx[b], idx[a], val);
}
int tre_lca(int a, int b){
    while(topf[a]!=topf[b]){
        if(dep[topf[a]]<dep[topf[b]]) swap(a,b);
        a=f[topf[a]][0];
    }
    if(dep[a]<dep[b]) return a;
    return b;
}
int tre_query(int a){
    return query(1, idx[a], idx[a]+sz[a]-1);
}
int get_son(int a, int b){
    for(int i=17;i>=0;--i)
        if(dep[f[b][i]]>dep[a]) b=f[b][i];
    return b;
}
int n,q,cap;
int main()
{
    scanf("%d %d", &n, &q);
    for(int i=1;i<n;++i){
        int a,b;
        scanf("%d %d", &a, &b);
        add_edge(a, b);
        add_edge(b, a);
    }
    for(int i=1;i<=n;++i) scanf("%d", &nod_val[i]);
    scanf("%d", &cap);
    dfs1(1, 1);
    dfs2(1, 1);
    buildt(1, 1, n);
    while(q--){
        int opt;
        scanf("%d", &opt);
        if(opt==1){
            scanf("%d", &cap);
        }else if(opt==2){
            int l,r,v;
            scanf("%d %d %d", &l, &r, &v);
            tre_change(l, r, v);
        }else if(opt==3){
            int t;
            scanf("%d", &t);
            int lca=tre_lca(t, cap);
            if(t==cap) printf("%d\n", query(1, 1, n));
            else if(lca!=t) printf("%d\n", tre_query(t));
            else{
                int son=get_son(t, cap);
                int ans=min(query(1, 1, idx[son]-1), query(1, idx[son]+sz[son], n)); // 除去中间那个区间,分左右区间求
                printf("%d\n", ans);
            }
        }else puts("Erro!");
    }
    return 0;
}
上一篇:【Python pypinyin】


下一篇:小程序处理富文本路径