• bzoj 3083 树链剖分


      首先我们先将树提出一个根变成有根树,那么我们可以通过树链剖分来实现对于子树的最小值求解,那么按照当前的根和询问的点的相对位置关系我们可以将询问变成某个子树和或者除去某颗子树之后其余的和,前者直接询问区间,后者询问区间的补集。

    /**************************************************************
        Problem: 3083
        User: BLADEVIL
        Language: C++
        Result: Accepted
        Time:6412 ms
        Memory:43904 kb
    ****************************************************************/
     
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define maxn 200010
    #define maxm 400010
    #define inf (~0U>>1)
     
    using namespace std;
     
    struct segment_tree {
        int left,right,min_,lazy;
    }t[maxn<<2];
     
    int n,m,l,rot,tot;
    int key[maxn];
    int other[maxm],pre[maxm],last[maxn];
    int size[maxn],max_son[maxn],top[maxn],dep[maxn],a[maxn],num[maxn][2],jump[maxn][20],dis[maxn];
     
    void connect(int x,int y) {
        pre[++l]=last[x];
        last[x]=l;
        other[l]=y;
    }
     
    void update(int x) {
        t[x].min_=min(t[x<<1].min_,t[(x<<1)+1].min_);
    }
     
    void push_down(int x) {
        t[x<<1].lazy=t[(x<<1)+1].lazy=t[x].lazy;
        t[x<<1].min_=t[(x<<1)+1].min_=t[x].min_;
        t[x].lazy=0;
    }
     
    int get_lca(int x,int y) {
        if (dis[x]>dis[y]) swap(x,y);
        int det=dis[y]-dis[x];
        for (int j=0;j<=18;j++)  if (det&(1<<j)) y=jump[y][j];
        if (x==y) return x;
        for (int j=18;j>=0;j--)
            if (jump[x][j]!=jump[y][j]) x=jump[x][j],y=jump[y][j];
        return jump[x][1];
    }
     
    int get_lca_son(int x,int y) {
        if (dis[x]>dis[y]) swap(x,y);
        for (int j=18;j>=0;j--)
            if (dis[jump[y][j]]>dis[x]) y=jump[y][j];
        return y;
    }
     
    void dfs(int x) {
        size[x]=1;
        for (int p=last[x];p;p=pre[p]) {
            if (dis[other[p]]) continue;
            jump[other[p]][0]=x; dis[other[p]]=dis[x]+1;
            dfs(other[p]);
            size[x]+=size[other[p]];
            if (size[other[p]]>size[max_son[x]]) max_son[x]=other[p];
        }
    }
     
    void make_segment(int x) {
        num[x][0]=++tot; a[tot]=key[x];
        if (max_son[x]) {
            top[max_son[x]]=top[x];
            dep[max_son[x]]=dep[x];
            make_segment(max_son[x]);
        }
        for (int p=last[x];p;p=pre[p]) {
            if (other[p]==jump[x][0]) continue;
            if (other[p]==max_son[x]) continue;
            top[other[p]]=other[p];
            dep[other[p]]=dep[x]+1;
            make_segment(other[p]);
        }
        num[x][1]=tot;
    }
     
    void build_segment(int x,int l,int r) {
        t[x].left=l; t[x].right=r;
        if (t[x].left==t[x].right) {
            t[x].min_=a[t[x].left];
            return ;
        }
        int mid=t[x].left+t[x].right>>1;
        build_segment(x<<1,l,mid); build_segment((x<<1)+1,mid+1,r);
        update(x);
    }
     
    void change_segment_tree(int x,int l,int r,int y) {
        if (t[x].lazy) push_down(x);
        if ((t[x].left==l)&&(t[x].right==r)) {
            t[x].lazy=t[x].min_=y;
            return ;
        }
        int mid=t[x].left+t[x].right>>1;
        if (l>mid) change_segment_tree((x<<1)+1,l,r,y); else
        if (r<=mid) change_segment_tree(x<<1,l,r,y); else
            change_segment_tree(x<<1,l,mid,y),change_segment_tree((x<<1)+1,mid+1,r,y);
        update(x);
    }
     
    void change(int x,int y,int z) {
        if (dep[x]>dep[y]) swap(x,y);
        while (dep[x]!=dep[y]) {
            change_segment_tree(1,num[top[y]][0],num[y][0],z);
            y=jump[top[y]][0];
        }
        while (top[x]!=top[y]) {
            change_segment_tree(1,num[top[x]][0],num[x][0],z);
            change_segment_tree(1,num[top[y]][0],num[y][0],z);
            x=jump[top[x]][0];
            y=jump[top[y]][0];
        }
        if (num[x][0]>num[y][0]) swap(x,y);
        change_segment_tree(1,num[x][0],num[y][0],z);
    }
     
    int query_segment_tree(int x,int l,int r) {
        if (l>r) return inf;
        if (t[x].lazy) push_down(x);
        if ((t[x].left==l)&&(t[x].right==r)) return t[x].min_;
        int mid=t[x].left+t[x].right>>1;
        if (l>mid) return query_segment_tree((x<<1)+1,l,r); else
        if (r<=mid) return query_segment_tree(x<<1,l,r); else
            return min(query_segment_tree(x<<1,l,mid),query_segment_tree((x<<1)+1,mid+1,r));
    }
     
    void query(int x) {
        if (x==rot) {
            printf("%d
    ",t[1].min_);
            return ;
        }
        if (get_lca(x,rot)!=x) printf("%d
    ",query_segment_tree(1,num[x][0],num[x][1])); else {
            int y=get_lca_son(x,rot);
            printf("%d
    ",min(query_segment_tree(1,1,num[y][0]-1),query_segment_tree(1,num[y][1]+1,n)));
            //printf("%d %d
    ",query_segment_tree(1,1,num[y][0]-1),query_segment_tree(1,num[y][1]+1,n));
            //printf("%d
    ",y);
            //printf("%d %d
    ",num[y][0],num[y][1]);
        }
    }
     
    int main() {
        //freopen("country.in","r",stdin); freopen("country.out","w",stdout);
        scanf("%d%d",&n,&m);
        for (int i=1;i<n;i++) {
            int x,y; scanf("%d%d",&x,&y);
            connect(x,y); connect(y,x);
        }
        for (int i=1;i<=n;i++) scanf("%d",&key[i]);
        scanf("%d",&rot);
        dis[rot]=1;
        dfs(rot);
        top[rot]=rot; dep[rot]=1;
        make_segment(rot);
        //for (int i=1;i<=n;i++) printf("%d %d %d %d %d
    ",i,max_son[i],size[i],num[i][0],num[i][1]);
        build_segment(1,1,n);
        for (int j=1;j<=18;j++)
            for (int i=1;i<=n;i++) jump[i][j]=jump[jump[i][j-1]][j-1];
        while (m--) {
            int opt; scanf("%d",&opt);
            if (opt==1) scanf("%d",&rot); else
            if (opt==2) {
                int l,r,y; scanf("%d%d%d",&l,&r,&y);
                change(l,r,y);
            } else {
                int x; scanf("%d",&x);
                query(x);
            }
        }
        return 0;
    }
  • 相关阅读:

    远见卓识,领导力在于把握企业潮流
    创业者白手起家需要的6个基本因素
    企业领袖的最高境界
    人才招聘中的“笔迹分析技术”
    个人品牌,无法复制的职场优势
    美丽的姑娘,请允许我为你写诗
    重做日志浪费(redo wastage)
    利用Toad for Data Analysts软件生成查询语句
    JailbreakMe.com最新浏览器模式破解iPhones,iPads和iPod Touches方法
  • 原文地址:https://www.cnblogs.com/BLADEVIL/p/3713417.html
Copyright © 2020-2023  润新知