• BZOJ_3083_遥远的国度_树链剖分+线段树


    BZOJ_3083_遥远的国度_树链剖分

    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


    总不能每次换根都对整个树剖一遍,因此我们要先以1为根进行树剖,然后对根的位置进行分类讨论。

    假设询问的时x,根为root。

    当root=x时直接输出整个树的最小值,这个必须要判而不能放到其他分类中。

    当root在x的子树外时,由于x的子树没有变,相当于还是查询x的子树。

    当root在x的子树内时,答案由两部分组成:

    1.x子树外,这个对应树剖序上两段区间。

    2.x子树内,需要刨去x到root路径上的点,我们对root不断跳重链,直到跳到x的儿子上,这个点的子树需要刨去,剩下的也是两段区间。

    分类讨论完成后直接树剖+线段树即可。

    注意权值可能爆int,需要用unsigned int

    代码:

    #include <stdio.h>
    #include <string.h>
    #include <algorithm>
    using namespace std;
    #define N 100050
    #define ls p<<1
    #define rs p<<1|1
    #define inf ((1u<<31)+1)
    typedef unsigned int un;
    int head[N],to[N<<1],nxt[N<<1],n,cnt,m;
    int son[N],fa[N],dep[N],siz[N],top[N],idx[N],root;
    un t[N<<2],tag[N<<2],val[N],a[N];
    inline void add(int u,int v) {
        to[++cnt]=v; nxt[cnt]=head[u]; head[u]=cnt;
    }
    void dfs1(int x,int y) {
        int i; fa[x]=y; dep[x]=dep[y]+1; siz[x]=1;
        for(i=head[x];i;i=nxt[i]) {
            if(to[i]!=y) {
                dfs1(to[i],x);
                siz[x]+=siz[to[i]];
                if(siz[to[i]]>siz[son[x]]) son[x]=to[i];
            }
        }
    }
    void dfs2(int x,int t) {
        top[x]=t; idx[x]=++idx[0];
        if(son[x]) dfs2(son[x],t);
        int i;
        for(i=head[x];i;i=nxt[i]) {
            if(to[i]!=fa[x]&&to[i]!=son[x]) dfs2(to[i],to[i]);
        }
    }
    void build(int l,int r,int p) {
        if(l==r) {
            t[p]=a[l]; return ;
        }
        int mid=(l+r)>>1;
        build(l,mid,ls); build(mid+1,r,rs);
        t[p]=min(t[ls],t[rs]);
    }
    inline void pushdown(int p) {
        if(tag[p]) {
            t[ls]=tag[ls]=tag[p];
            t[rs]=tag[rs]=tag[p];
            tag[p]=0;
        }
    }
    void update(int l,int r,int x,int y,un v,int p) {
        if(x<=l&&y>=r) {
            t[p]=v; tag[p]=v; return ;
        }
        pushdown(p);
        int mid=(l+r)>>1;
        if(x<=mid) update(l,mid,x,y,v,ls);
        if(y>mid) update(mid+1,r,x,y,v,rs);
        t[p]=min(t[ls],t[rs]);
    }
    un qmin(int l,int r,int x,int y,int p) {
        if(x<=l&&y>=r) return t[p];
        pushdown(p);
        int mid=(l+r)>>1;
        un re=inf;
        if(x<=mid) re=min(re,qmin(l,mid,x,y,ls));
        if(y>mid) re=min(re,qmin(mid+1,r,x,y,rs));
        return re;
    }
    un solve(int x,int y) {
        un re=inf;
        if(idx[x]<=idx[y]-1) re=min(re,qmin(1,n,idx[x],idx[y]-1,1));
        if(idx[y]+siz[y]<=idx[x]+siz[x]-1) re=min(re,qmin(1,n,idx[y]+siz[y],idx[x]+siz[x]-1,1));
        return re;
    }
    int main() {
        scanf("%d%d",&n,&m);
        int i,x,y,opt;
        un z;
        for(i=1;i<n;i++) {
            scanf("%d%d",&x,&y);
            add(x,y); add(y,x);
        }
        for(i=1;i<=n;i++) scanf("%u",&i[val]);
        scanf("%d",&root);
        dfs1(1,0);
        dfs2(1,1);
        for(i=1;i<=n;i++) a[idx[i]]=val[i];
        build(1,n,1);
        while(m--) {
            scanf("%d%d",&opt,&x);
            if(opt==1) {
                root=x;
            }else if(opt==2) {
                scanf("%d%u",&y,&z);
                while(top[x]!=top[y]) {
                    if(dep[top[x]]>dep[top[y]]) swap(x,y);
                    update(1,n,idx[top[y]],idx[y],z,1);
                    y=fa[top[y]];
                }
                if(dep[x]<dep[y]) swap(x,y);
                update(1,n,idx[y],idx[x],z,1);
            }else {
                if(root==x) {
                    printf("%d
    ",t[1]);
                }else if(idx[root]<idx[x]||idx[root]>idx[x]+siz[x]-1) {
                    printf("%u
    ",qmin(1,n,idx[x],idx[x]+siz[x]-1,1));
                }else {
                    un re=inf;
                    if(1<=idx[x]-1) re=min(re,qmin(1,n,1,idx[x]-1,1));
                    if(idx[x]+siz[x]<=n) re=min(re,qmin(1,n,idx[x]+siz[x],n,1));
                    int y=root;
                    if(fa[y]==x) {
                        re=min(re,solve(x,y));
                    }else {
                        if(top[y]==top[x]) {
                            re=min(re,solve(x,son[x]));
                        }else {
                            while(fa[y]!=x) {
                                y=fa[y];
                                if(fa[y]==x) break;
                                if(top[x]==top[y]) break;
                                y=top[y];
                            }
                            while(fa[y]!=x) y=fa[y];
                            re=min(re,solve(x,y));
                        }
                    }
                    printf("%u
    ",re);
                }
            }
        }
    }
    
  • 相关阅读:
    基于udp简单聊天的系统
    网络编程_tcp与dup协议简单应用
    logging_modules
    linux内核配置与编译
    linux内核简介
    对于国嵌上学期《一跃进入C大门》Mini2440的代码修正
    通过按键玩中断
    MMU功能解析、深入剖析、配置与使用
    C与汇编混合编程
    一跃进入C大门
  • 原文地址:https://www.cnblogs.com/suika/p/9062604.html
Copyright © 2020-2023  润新知