zoukankan      html  css  js  c++  java
  • BZOJ3083 遥远的国度 【树链剖分】

    BZOJ3083 遥远的国度


    Description

    zcwwzdjn在追杀十分sb的zhx,而zhx逃入了一个遥远的国度。当zcwwzdjn准备进入遥远的国度继续追杀时,守护神RapiD阻拦了zcwwzdjn的去路,他需要zcwwzdjn完成任务后才能进入遥远的国度继续追杀。
    问题是这样的:遥远的国度有n个城市,这些城市之间由一些路连接且这些城市构成了一颗树。这个国度有一个首都,我们可以把这个首都看做整棵树的根,但遥远的国度比较奇怪,首都是随时有可能变为另外一个城市的。遥远的国度的每个城市有一个防御值,有些时候RapiD会使得某两个城市之间的路径上的所有城市的防御值都变为某个值。RapiD想知道在某个时候,如果把首都看做整棵树的根的话,那么以某个城市为根的子树的所有城市的防御值最小是多少。由于RapiD无法解决这个问题,所以他拦住了zcwwzdjn希望他能帮忙。但zcwwzdjn还要追杀sb的zhx,所以这个重大的问题就被转交到了你的手上。

    Input

    第1行两个整数n m,代表城市个数和操作数。
    第2行至第n行,每行两个整数 u v,代表城市u和城市v之间有一条路。
    第n+1行,有n个整数,代表所有点的初始防御值。
    第n+2行一个整数 id,代表初始的首都为id。
    第n+3行至第n+m+2行,首先有一个整数opt,如果opt=1,接下来有一个整数id,代表把首都修改为id;如果opt=2,接下来有三个整数p1 p2 v,代表将p1 p2路径上的所有城市的防御值修改为v;如果opt=3,接下来有一个整数 id,代表询问以城市id为根的子树中的最小防御值。

    Output

    对于每个opt=3的操作,输出一行代表对应子树的最小点权值。

    Sample Input

    3 7
    1 2
    1 3
    1 2 3
    1
    3 1
    2 1 1 6
    3 1
    2 2 2 5
    3 1
    2 3 3 4
    3 1

    Sample Output

    1
    2
    3
    4

    HINT

    对于20%的数据,n<=1000 m<=1000。
    对于另外10%的数据,n<=100000,m<=100000,保证修改为单点修改。
    对于另外10%的数据,n<=100000,m<=100000,保证树为一条链。
    对于另外10%的数据,n<=100000,m<=100000,没有修改首都的操作。
    对于100%的数据,n<=100000,m<=100000,0<所有权值<=2^31。


    树链剖分维护子树信息

    我们可以发现在树链剖分的dfs序中,子树所在的区间是连续的,所以我们可以直接在数据结构上查询子树信息

    然后在换根的时候需要判断一下节点和根的位置关系,令查询节点为t,根为root
    * 当root是t的子树时,答案是所有节点抛去在root到t链上t的儿子节点的子树答案
    * 当root与t相等时,答案就是整棵树的答案
    * 当root不在t的子树(包括t)时,答案就是t子树的答案

    然后分类讨论一下就好了


    #include<bits/stdc++.h>
    using namespace std;
    #define N 200010
    #define LL long long
    inline LL read(){
        LL ans=0,w=1;char ch=getchar();
        while(ch!='-'&&!isdigit(ch))ch=getchar();
        if(ch=='-')w=-1,ch=getchar();
        while(isdigit(ch))ans=ans*10+ch-'0',ch=getchar();
        return ans*w;
    }
    const LL INF=1e17;
    struct Edge{int v,next;}E[N<<1];
    int head[N],tot=0,ind=0;
    int siz[N],hson[N],dep[N],fa[N],top[N],num[N],pre[N];
    int n,m,a[N];
    void add(int u,int v){
        E[++tot]=(Edge){v,head[u]};
        head[u]=tot;
    }
    void dfs1(int u,int father){
        siz[u]=1;
        hson[u]=0;
        fa[u]=father;
        dep[u]=dep[father]+1;
        for(int i=head[u];i;i=E[i].next){
            int v=E[i].v;
            if(v==father)continue;
            dfs1(v,u);
            siz[u]+=siz[v];
            if(siz[v]>siz[hson[u]])hson[u]=v;
        }
    }
    void dfs2(int u,int tp){
        num[u]=++ind;
        pre[ind]=u;
        top[u]=tp;
        if(hson[u])dfs2(hson[u],tp);
        for(int i=head[u];i;i=E[i].next){
            int v=E[i].v;
            if(v==fa[u]||v==hson[u])continue;
            dfs2(v,v);
        }
    }
    //segment-tree
    #define LD (o<<1)
    #define RD ((o<<1)|1)
    int l[N<<2],r[N<<2];
    LL minv[N<<2],change[N<<2];
    void pushup(int o){
        minv[o]=min(minv[LD],minv[RD]);
    }
    void pushdown(int o){
        if(change[o]&&l[o]!=r[o]){
            change[LD]=change[RD]=change[o];
            minv[LD]=minv[RD]=change[o];
            change[o]=0;
        }
    }
    void build(int o,int ll,int rr){
        l[o]=ll;r[o]=rr;
        if(ll==rr){minv[o]=a[pre[ll]];return;}
        int mid=(ll+rr)>>1;
        build(LD,ll,mid);
        build(RD,mid+1,rr);
        pushup(o);
    }
    void modify(int o,int ll,int rr,LL val){
        if(rr<ll)return;
        if(ll==l[o]&&rr==r[o]){minv[o]=change[o]=val;return;}
        pushdown(o);
        int mid=(l[o]+r[o])>>1;
        if(mid>=rr)modify(LD,ll,rr,val);
        else if(mid<ll)modify(RD,ll,rr,val);
        else modify(LD,ll,mid,val),modify(RD,mid+1,rr,val);
        pushup(o);
    }
    LL query(int o,int ll,int rr){
        if(rr<ll)return INF;
        if(ll<=l[o]&&r[o]<=rr)return minv[o];
        pushdown(o);
        int mid=(l[o]+r[o])>>1;
        if(mid>=rr)return query(LD,ll,rr);
        else if(mid<ll)return query(RD,ll,rr);
        else return min(query(LD,ll,mid),query(RD,mid+1,rr));
    }
    void modify_tree(int x,int y,LL val){
        while(top[x]!=top[y]){
            if(dep[top[x]]<dep[top[y]])swap(x,y);
            modify(1,num[top[x]],num[x],val);
            x=fa[top[x]];
        }
        if(dep[x]<dep[y])swap(x,y);
        modify(1,num[y],num[x],val);
    }
    int lca(int x,int y){
        while(top[x]!=top[y]){
            if(dep[top[x]]<dep[top[y]])swap(x,y);
            x=fa[top[x]];
        }
        if(dep[x]<dep[y])return x;
        else return y;
    }
    int findson(int x,int y){
        while(top[x]!=top[y]){
            if(dep[top[x]]<dep[top[y]])swap(x,y);
            if(fa[top[x]]==y)return top[x];
            x=fa[top[x]];
        }
        if(dep[x]<dep[y])swap(x,y);
        return hson[y];
    }
    LL query_tree(int x,int y){
        if(x==y)return query(1,1,n);
        else if(lca(x,y)!=y)return query(1,num[y],num[y]+siz[y]-1);
        else{
            int tmp=findson(x,y);
            return min(query(1,1,num[tmp]-1),query(1,num[tmp]+siz[tmp],n));
        }
    }
    int main(){
        n=read();m=read();
        for(int i=1;i<n;i++){
            int u=read(),v=read();
            add(u,v);add(v,u);
        }
        for(int i=1;i<=n;i++)a[i]=read();
        dfs1(1,0);
        dfs2(1,1);
        build(1,1,n);
        int lastid;scanf("%d",&lastid);
        for(int i=1;i<=m;i++){
            int op;scanf("%d",&op);
            if(op==1){
                int x;scanf("%d",&x);
                lastid=x;
            }
            if(op==2){
                int x,y;LL val;
                scanf("%d%d%lld",&x,&y,&val);
                modify_tree(x,y,val);
            } 
            if(op==3){
                int x;scanf("%d",&x);
                printf("%lld
    ",query_tree(lastid,x));
            } 
        }
        return 0;
    }
  • 相关阅读:
    学习链接
    【转】C#学习路线WinForm学习路线
    WPF 等待动画控件
    wpf 设置窗体在屏幕的初始位置
    WPF 添加右键菜单 自定义透明控件
    记录自己的点滴
    Linux下的mysql默认大小写敏感
    springboot+mybatis遇到BUG:自动注入失败
    springboot在阿里CentOS 7后台永久运行
    阿里云CentOS7 64位安装jdk8和mysql5.6.43及远程连接mysql
  • 原文地址:https://www.cnblogs.com/dream-maker-yk/p/9676366.html
Copyright © 2011-2022 走看看