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
    提示
    对于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。

    题解Here!
    三种操作:换根,区间修改,子树最小值。
    如果没有换根,这就是一道树剖的沙茶题。
    但是有换根呢?
    我们仍然以$1$为根建树。
    然后我们分类讨论一下:
    1. 如果$now==root$ ,那就是查询整棵树 ,直接输出$queryunderline min(1,n)$就好了。
    2. 如果$LCA(now,root)!=now$,这时根与$now$没有关系,直接查询$now$的子树即可。
    3. 如果$LCA(now,root)==now$,这时比较麻烦。
    我们可以先找一下$now$的所有儿子。
    由于一个子树的$dfs$序是连续的。
    所以,如果这个儿子的$id$小于等于$id[root]$,并且这个子树中的最大$dfs$序($id[son]+size[son]-1$)大于等于当前的$id[root]$。
    那么就可以判断出$root$在这个儿子中或者就是这个儿子,记录下这个儿子。
    还是那句话 :一个子树的$dfs$序是连续的。
    这时$now$的子树就是去除包含$root$的那个儿子的子树的整棵树了。
    当然,这题也可以用$LCT$维护子树信息做,只不过我不会啊。。。
    附代码:
    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #define LSON rt<<1
    #define RSON rt<<1|1
    #define DATA(x) b[x].data
    #define SIGN(x) b[x].c
    #define LSIDE(x) b[x].l
    #define RSIDE(x) b[x].r
    #define WITDH(x) (RSIDE(x)-LSIDE(x)+1)
    #define MAXN 100010
    #define MAX (1LL<<62)
    using namespace std;
    int n,m,c=1,d=1,root;
    int val[MAXN],head[MAXN],deep[MAXN],son[MAXN],size[MAXN],fa[MAXN],id[MAXN],pos[MAXN],top[MAXN];
    struct Tree{
        int next,to;
    }a[MAXN<<1];
    struct Segmeng_Tree{
        long long data,c;
        int l,r;
    }b[MAXN<<2];
    inline int read(){
        int date=0,w=1;char c=0;
        while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
        while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
        return date*w;
    }
    inline void pushup(int rt){
        DATA(rt)=min(DATA(LSON),DATA(RSON));
    }
    inline void pushdown(int rt){
        if(SIGN(rt)==-1||LSIDE(rt)==RSIDE(rt))return;
        SIGN(LSON)=DATA(LSON)=SIGN(rt);
        SIGN(RSON)=DATA(RSON)=SIGN(rt);
        SIGN(rt)=-1;
    }
    void buildtree(int l,int r,int rt){
        LSIDE(rt)=l;RSIDE(rt)=r;SIGN(rt)=-1;
        if(l==r){
            DATA(rt)=val[pos[l]];
            return;
        }
        int mid=l+r>>1;
        buildtree(l,mid,LSON);
        buildtree(mid+1,r,RSON);
        pushup(rt);
    }
    void update(int l,int r,long long c,int rt){
        if(l<=LSIDE(rt)&&RSIDE(rt)<=r){
            SIGN(rt)=DATA(rt)=c;
            return;
        }
        pushdown(rt);
        int mid=LSIDE(rt)+RSIDE(rt)>>1;
        if(l<=mid)update(l,r,c,LSON);
        if(mid<r)update(l,r,c,RSON);
        pushup(rt);
    }
    long long query(int l,int r,int rt){
        long long ans=MAX;
        if(l<=LSIDE(rt)&&RSIDE(rt)<=r)return DATA(rt);
        pushdown(rt);
        int mid=LSIDE(rt)+RSIDE(rt)>>1;
        if(l<=mid)ans=min(ans,query(l,r,LSON));
        if(mid<r)ans=min(ans,query(l,r,RSON));
        return ans;
    }
    inline void add(int x,int y){
        a[c].to=y;a[c].next=head[x];head[x]=c++;
        a[c].to=x;a[c].next=head[y];head[y]=c++;
    }
    void dfs1(int rt){
        son[rt]=0;size[rt]=1;
        for(int i=head[rt];i;i=a[i].next){
            int will=a[i].to;
            if(!deep[will]){
                deep[will]=deep[rt]+1;
                fa[will]=rt;
                dfs1(will);
                size[rt]+=size[will];
                if(size[son[rt]]<size[will])son[rt]=will;
            }
        }
    }
    void dfs2(int rt,int f){
        id[rt]=d++;pos[id[rt]]=rt;top[rt]=f;
        if(son[rt])dfs2(son[rt],f);
        for(int i=head[rt];i;i=a[i].next){
            int will=a[i].to;
            if(will!=fa[rt]&&will!=son[rt])dfs2(will,will);
        }
    }
    int LCA(int x,int y){
        while(top[x]!=top[y]){
            if(deep[top[x]]<deep[top[y]])swap(x,y);
            x=fa[top[x]];
        }
        if(deep[x]>deep[y])swap(x,y);
        return x;
    }
    void solve_update(int x,int y,int k){
        while(top[x]!=top[y]){
            if(deep[top[x]]<deep[top[y]])swap(x,y);
            update(id[top[x]],id[x],k,1);
            x=fa[top[x]];
        }
        if(deep[x]>deep[y])swap(x,y);
        update(id[x],id[y],k,1);
    }
    void solve_query(int x){
        if(x==root)printf("%lld
    ",query(1,n,1));
        else{
            int lca=LCA(x,root);
            if(lca==x){
                int y;
                for(int i=head[x];i;i=a[i].next){
                    int will=a[i].to;
                    if(id[will]<=id[root]&&id[root]<=id[will]+size[will]-1){y=will;break;}
                }
                long long s=min(query(1,id[y]-1,1),query(id[y]+size[y],n,1));
                printf("%lld
    ",s);
            }
            else printf("%lld
    ",query(id[x],id[x]+size[x]-1,1));
        }
    }
    void work(){
        int f,x,y,k;
        while(m--){
            f=read();x=read();
            if(f==1){
                root=x;
            }
            else if(f==2){
                y=read();k=read();
                solve_update(x,y,k);
            }
            else solve_query(x);
        }
    }
    void init(){
        int x,y;
        n=read();m=read();
        for(int i=1;i<n;i++){
            x=read();y=read();
            add(x,y);
        }
        for(int i=1;i<=n;i++)val[i]=read();
        root=read();
        deep[1]=1;
        dfs1(1);
        dfs2(1,1);
        buildtree(1,n,1);
    }
    int main(){
        init();
        work();
        return 0;
    }
    
  • 相关阅读:
    PBRT笔记(3)——KD树
    PBRT笔记(2)——BVH
    PBRT笔记(1)——主循环、浮点误差
    《Ray Tracing in One Weekend》、《Ray Tracing from the Ground Up》读后感以及光线追踪学习推荐
    在Node.js中使用ffi调用dll
    Node.js c++ 扩展之HelloWorld
    在Qt中配置TBB以及简单实用
    对《将Unreal4打包后的工程嵌入到Qt或者桌面中》一文的补充
    QtQuick大坑笔记之Http的Get与Post操作(带cookie)
    QtQuick自定义主题以及控件样式指引
  • 原文地址:https://www.cnblogs.com/Yangrui-Blog/p/9471542.html
Copyright © 2011-2022 走看看