zoukankan      html  css  js  c++  java
  • bzoj 3083: 遥远的国度(树上换根操作,树剖+询问整个子树)

    bzoj 3083

    3083: 遥远的国度Time Limit: 10 Sec Memory Limit: 1280 MB

    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。

    题解

    这一题首先肯定要树剖,可是怎样处理询问整个子树的操作呢,其实在树剖过程中得到的 (p[i]),其实对于每个结点 (i) 的子树, (p[i]) 是连续的!

    对于换根操作,当然是不能真的换根,我们可以一直以1为根进行参考,对以1为根的树进行剖分后,以 (i) 为根的子树中最小的 (p[i])(in[i]),最大的 (p[i])(out[i]),假如当前树根为 (cur),询问 (u) 的子树:

    (1)若 (cur==u) ,则是询问整棵树。

    (2)若 (cur) 不属于 (u) 的子树,那么此时以 (cur) 为根的树中 (u) 的子树就是以1为根的树中 (u) 的子树。

    (3)若 (cur) 属于 (u) 的子树,设 (t)(u) 的儿子,且在 (u)(cur) 的路径上

    那么画一画就知道,查询范围应该是 ([1,in[t]-1],[out[t]+1,n]).

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<vector>
    #include<queue>
    #include<stack>
    using namespace std;
    #define rep(i,a,n) for (int i=a;i<n;i++)
    #define per(i,a,n) for (int i=n-1;i>=a;i--)
    #define pb push_back
    #define fi first
    #define se second
    #define dbg(...) cerr<<"["<<#__VA_ARGS__":"<<(__VA_ARGS__)<<"]"<<endl;
    typedef vector<int> VI;
    typedef long long ll;
    typedef pair<int,int> PII;
    const int inf=0x3fffffff;
    const ll mod=1000000007;
    const int maxn=1e5+10;
    int v[maxn];
    
    int fa[maxn],top[maxn],son[maxn],num[maxn],p[maxn],dep[maxn],fp[maxn];
    //top[v]表示v所在的重链的顶端节点,对于u的轻儿子v有top[v]=v,fa[v]表示v的父亲节点,num[v]表示以v为根的子树的节点数,p[v]表示v与其父亲节点的连边在线段树中的位置,son[v]为v的重儿子,dep为深度
    
    struct node
    {
        int mi,lazy;
    }seg[maxn*4];
    
    void up(int i)
    {
        seg[i].mi=min(seg[i*2].mi,seg[i*2+1].mi);
    }
    void pushdown(int i)
    {
        if(seg[i].lazy)
        {
            seg[i*2].lazy=seg[i*2].mi=seg[i].lazy;
            seg[i*2+1].lazy=seg[i*2+1].mi=seg[i].lazy;
            seg[i].lazy=0;
        }
    }
    void build(int i,int l,int r)
    {
        seg[i].lazy=0;
        if(l==r)
        {
            seg[i].mi=v[fp[l]];
            return;
        }
        int m=(l+r)/2;
        build(i*2,l,m),build(i*2+1,m+1,r);
        up(i);
    }
    
    void update(int i,int l,int r,int L,int R,int v)
    {
        if(l==L&&r==R)
        {
            seg[i].lazy=v;
            seg[i].mi=v;
            return;
        }
        pushdown(i);
        int m=(L+R)/2;
        if(r<=m) update(i*2,l,r,L,m,v);
        else if(l>m) update(i*2+1,l,r,m+1,R,v);
        else
        {
            update(i*2,l,m,L,m,v);
            update(i*2+1,m+1,r,m+1,R,v);
        }
        up(i);
    }
    
    int query(int i,int l,int r,int L,int R)
    {
        if(l==L&&r==R)
        {
            return seg[i].mi;
        }
        if(seg[i].lazy) return seg[i].lazy;
        pushdown(i);
        int m=(L+R)/2;
        if(r<=m) return query(i*2,l,r,L,m);
        else if(l>m) return query(i*2+1,l,r,m+1,R);
        else
        {
            return min(query(i*2,l,m,L,m),query(i*2+1,m+1,r,m+1,R));
        }
    }
    
    int head[maxn];
    struct edge
    {
        int to,next;
    }e[maxn*2];   //
    int tol=0;
    void add(int u,int v)
    {
        e[++tol].to=v,e[tol].next=head[u],head[u]=tol;
    }
    
    int in[maxn],out[maxn];
    int pos;//线段树总区间大小
    void dfs(int u,int f,int d)
    {
        num[u]=1;
        fa[u]=f;
        dep[u]=d;
        for(int i=head[u];i;i=e[i].next)
        {
            int v=e[i].to;
            if(v==f) continue;
            dfs(v,u,d+1);
            if(son[u]==0||num[v]>num[son[u]])
                son[u]=v;
            num[u]+=num[v];
        }
    }
    void dfs2(int u,int sp)
    {
        top[u]=sp;
        if(son[u])
        {
            p[u]=pos;
            fp[pos]=u;
            in[u]=out[u]=pos;
            pos++;
            dfs2(son[u],sp);
            in[u]=min(in[u],in[son[u]]);
            out[u]=max(out[u],out[son[u]]);
        }
        else    //叶子结点
        {
            p[u]=pos;
            fp[pos]=u;
            in[u]=out[u]=pos;
            pos++;
            return;
        }
        for(int i=head[u];i;i=e[i].next)
        {
            int v=e[i].to;
            if(v!=son[u]&&v!=fa[u])
            {
                dfs2(v,v);
                in[u]=min(in[u],in[v]);
                out[u]=max(out[u],out[v]);
            }
        }
    }
    void init()
    {
        pos=1;
        memset(fa,0,sizeof(fa));
        memset(son,0,sizeof(son));
    }
    void change(int u,int v,int n,int w)
    {
        int f1=top[u],f2=top[v];
        while(f1!=f2)
        {
            if(dep[f1]<dep[f2])
            {
                swap(f1,f2);
                swap(u,v);
            }
            update(1,p[f1],p[u],1,n,w);
            u=fa[f1],f1=top[u];
        }
        if(dep[u]>dep[v]) swap(u,v);
        update(1,p[u],p[v],1,n,w);
    }
    
    int f1[maxn][18];
    void bfs(int rt)
    {
        queue<int> q;
        dep[rt] = 1;
        f1[rt][0] = rt;
        q.push(rt);
        while(!q.empty())
        {
            int t = q.front();
            q.pop();
            for(int i = 1 ; i <= 17 ; i++)
                f1[t][i] = f1[f1[t][i-1]][i-1];
            for(int i = head[t] ; i ; i = e[i].next)
            {
                int v = e[i].to;
                if(v == f1[t][0])continue;
                dep[v] = dep[t]+1;
                f1[v][0] = t;
                q.push(v);
            }
        }
    }
    int get_up(int u,int k)
    {
        int tu=u;
        for(int det = k, i = 0; det ;det>>=1, i++)
            if(det&1)
                tu = f1[tu][i];
        return tu;
    }
    
    int main()
    {
        init();
        int n,m;
        scanf("%d%d",&n,&m);
        rep(i,1,n+1) in[i]=1e9,out[i]=0;
        rep(i,1,n)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            add(u,v),add(v,u);
        }
        rep(i,1,n+1) scanf("%d",&v[i]);
        int cur;
        scanf("%d",&cur);
        bfs(1);
        dfs(1,0,1);
        dfs2(1,1);
        build(1,1,n);
        while(m--)
        {
            int op,u,v,w;
            scanf("%d",&op);
            if(op==1)
            {
                scanf("%d",&cur);
            }
            else if(op==2)
            {
                scanf("%d%d%d",&u,&v,&w);
                change(u,v,n,w);
            }
            else if(op==3)
            {
                scanf("%d",&u);
                int ans=1e9;
                if(u==cur)
                    ans=seg[1].mi;
                else if(in[u]<=in[cur]&&out[cur]<=out[u])
                {
                    int k=dep[cur]-dep[u]-1;
                    int tv=get_up(cur,k);
                    if(in[tv]>1)
                    ans=min(ans,query(1,1,in[tv]-1,1,n));
                    if(out[tv]<n)
                    ans=min(ans,query(1,out[tv]+1,n,1,n));
                }
                else
                    ans=query(1,in[u],out[u],1,n);
                printf("%d
    ",ans);
            }
        }
        return 0;
    }
    
  • 相关阅读:
    OSG-提示“error reading file e:1.jpg file not handled”
    OSG-加载地球文件报0x00000005错误,提示error reading file simple.earth file not handled
    QT-找开工程后,最上方提示the code model could not parse an included file, which might lead to incorrect code completion and highlighting, for example.
    我的书《Unity3D动作游戏开发实战》出版了
    java中无符号类型的第三方库jOOU
    Windows批处理备份mysql数据
    使用 DevTools 时,通用Mapper经常会出现 class x.x.A cannot be cast to x.x.A
    Java版本,Java版本MongoDB驱动,驱动与MongoDB数据库,Spring之间的兼容性
    Jrebel本地激活方法
    wget下载指定网站目录下的所有内容
  • 原文地址:https://www.cnblogs.com/tarjan/p/7629987.html
Copyright © 2011-2022 走看看