首页 > 其他 > 详细

BZOJ3083 遥远的国度

时间:2018-09-14 10:20:09      阅读:162      评论:0      收藏:0      [点我收藏+]

题意

遥远的国度有n个城市,这些城市之间由一些路连接且这些城市构成了一颗树。这个国度有一个首都,我们可以把这个首都看做整棵树的根,但遥远的国度比较奇怪,首都是随时有可能变为另外一个城市的。遥远的国度的每个城市有一个防御值,有些时候RapiD会使得某两个城市之间的路径上的所有城市的防御值都变为某个值。RapiD想知道在某个时候,如果把首都看做整棵树的根的话,那么以某个城市为根的子树的所有城市的防御值最小是多少。

\(n \leq 100000,m \leq 100000\)

分析

重点在换根。
其实是假的换根,每次判断一下根和询问节点的关系即可。
修改使用树链剖分。
查询判断后用线段树查询。

判断关系的方法:

  1. x=root,查询整棵树
  2. lca(x,root)!=x,即root不在x的子树中,查询x的子树
  3. lca(x,root)=x,即root在x的子树中,找到root具体在x的哪颗子树里面,查询该子树对整棵树的补集

时间复杂度\(O(N \log N+M \log^2 N)\)

代码

#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<ctime>
#include<iostream>
#include<string>
#include<vector>
#include<list>
#include<deque>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<complex>
#pragma GCC optimize ("O0")
using namespace std;
template<class T> inline T read(T&x)
{
    T data=0;
    int w=1;
    char ch=getchar();
    while(!isdigit(ch))
    {
        if(ch==‘-‘)
            w=-1;
        ch=getchar();
    }
    while(isdigit(ch))
        data=10*data+ch-‘0‘,ch=getchar();
    return x=data*w;
}
typedef long long ll;
const int INF=0x7fffffff;

const int MAXN=1e5+7;
int n;

struct Edge
{
    int nx,to;
}E[MAXN<<1];
int head[MAXN],ecnt;

void addedge(int x,int y)
{
    E[++ecnt].to=y;
    E[ecnt].nx=head[x],head[x]=ecnt;
}

int a[MAXN];
int fa[MAXN],sz[MAXN],dep[MAXN],son[MAXN];
int top[MAXN],clk,dfn[MAXN];
int w[MAXN];

void dfs1(int x,int f)
{
    fa[x]=f,sz[x]=1,dep[x]=dep[f]+1;
    for(int i=head[x];i;i=E[i].nx)
    {
        int y=E[i].to;
        if(y==f)
            continue;
        dfs1(y,x);
        sz[x]+=sz[y]; // edit 1,order of +=size and dfs1
        if(sz[y]>sz[son[x]])
            son[x]=y;
    }
}

void dfs2(int x,int topf)
{
    top[x]=topf;
    dfn[x]=++clk;
    w[clk]=a[x];
    if(!son[x])
        return;
    dfs2(son[x],topf);
    for(int i=head[x];i;i=E[i].nx)
    {
        int y=E[i].to;
        if(y==fa[x]||y==son[x])
            continue;
        dfs2(y,y);
    }
}

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]];
    }
    return dep[x]<dep[y]?x:y;
}

struct SegTree
{
    int minv[MAXN<<2];
    int setv[MAXN<<2];
#define lson (now<<1)
#define rson (now<<1|1)
    void pushup(int now)
    {
        minv[now]=min(minv[lson],minv[rson]);
    }
    
    void pushdown(int now)
    {
        if(setv[now])
        {
            minv[lson]=setv[now],
            setv[lson]=setv[now];
            minv[rson]=setv[now],
            setv[rson]=setv[now];
            setv[now]=0;
        }
    }
    
    void build(int now,int l,int r)
    {
        setv[now]=0;
        if(l==r)
        {
            minv[now]=w[l];
            return;
        }
        int mid=(l+r)>>1;
        build(lson,l,mid);
        build(rson,mid+1,r);
        pushup(now);
    }
    
    void set(int now,int l,int r,int ql,int qr,int v)
    {
        if(ql<=l&&r<=qr)
        {
            minv[now]=v,
            setv[now]=v;
            return;
        }
        pushdown(now);
        int mid=(l+r)>>1;
        if(ql<=mid)
            set(lson,l,mid,ql,qr,v);
        if(qr>=mid+1)
            set(rson,mid+1,r,ql,qr,v);
        pushup(now);
    }
    
    int qmin(int now,int l,int r,int ql,int qr)
    {
        if(ql<=l&&r<=qr)
        {
            return minv[now];
        }
        pushdown(now);
        int mid=(l+r)>>1,ans=INF;
        if(ql<=mid)
            ans=min(ans,qmin(lson,l,mid,ql,qr));
        if(qr>=mid+1) // edit 1
            ans=min(ans,qmin(rson,mid+1,r,ql,qr));
        return ans;
    }
}T;

void setpath(int x,int y,int v)
{
    while(top[x]!=top[y])
    {
        if(dep[top[x]]<dep[top[y]])
            swap(x,y);
        T.set(1,1,n,dfn[top[x]],dfn[x],v);
        x=fa[top[x]];
    }
    if(dep[x]>dep[y])
        swap(x,y);
    T.set(1,1,n,dfn[x],dfn[y],v);
}

int find(int x,int r)
{
    int t;
    while(top[r]!=top[x])
    {
        t=top[r],
        r=fa[top[r]];
    }
    if(r==x)
        return t;
    else
        return son[x];
}
/*
8 999
1 2
2 3
2 4
4 8
4 5
1 6
6 7
2 3 5 11 10 6 9 12
1
3 2
2 5 6 7
3 2
*/
int main()
{
//  freopen("BZOJ3083.in","r",stdin);
//  freopen("BZOJ3083.out","w",stdout);
    int m;
    read(n);read(m);
    for(int i=1;i<n;++i)
    {
        int x,y;
        read(x);read(y);
        addedge(x,y);
        addedge(y,x);
    }
//  cerr<<"edge end"<<endl;
    for(int i=1;i<=n;++i)
        read(a[i]);
//  cerr<<"a end"<<endl;
    int r;
    read(r);
    dfs1(r,0);
    dfs2(r,r);
/*  cerr<<"dfn check"<<endl;
    for(int i=1;i<=n;++i)
        cerr<<i<<" dfn="<<dfn[i]<<endl;*/
    T.build(1,1,n);
//  cerr<<"init end"<<endl;
    while(m--)
    {
        int opt;
        read(opt);
        if(opt==1)
        {
            read(r);
        }
        else if(opt==2)
        {
//          cerr<<"modifying"<<endl;
            int x,y,v;
            read(x);read(y);read(v);
            setpath(x,y,v);
        }
        else if(opt==3)
        {
            int x,ans;
            read(x);
            if(r==x)
            {
                ans=T.minv[1];
            }
            else
            {
                int f=lca(r,x);
                if(f!=x)
                {
                    ans=T.qmin(1,1,n,dfn[x],dfn[x]+sz[x]-1);
                }
                else
                {
                    int y=find(x,r);
                    ans=INF;
                    if(1<=dfn[y]-1)
                        ans=min(ans,T.qmin(1,1,n,1,dfn[y]-1));
                    if(dfn[y]+sz[y]<=n)
                        ans=min(ans,T.qmin(1,1,n,dfn[y]+sz[y],n));
                }
            }
            printf("%d\n",ans);
/*          cerr<<"cur weight check"<<endl;
            for(int i=1;i<=n;++i)
                cerr<<i<<"  w="<<T.qmin(1,1,n,dfn[i],dfn[i])<<endl;*/
        }
    }
//  fclose(stdin);
//  fclose(stdout);
    return 0;
}

Hint

大家不要学我把dfs1sz[x]+=sz[y]的顺序打反了,为此我调了一天。

BZOJ3083 遥远的国度

原文:https://www.cnblogs.com/autoint/p/9644611.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!