zoukankan      html  css  js  c++  java
  • BZOJ5288 HNOI/AHOI2018游戏

      首先将之间没有锁的房间合并。显然可达性具有传递性和反交换律(即若a能到达b,则b不能到达a)。

      考虑对每个房间找到其左右第一个(即与其最接近的)能作为起点到达它的房间。如果能求出这个,对此建两棵树,问题就变为终点是否在起点的子树内。

      容易想到单调栈。不妨考虑求左边第一个。栈内维护当前房间左边能作为起点到达它的房间。一旦栈顶的房间不能再到达当前点,显然其也不能再到达之后的点。而如果栈顶的房间能到达当前点,栈里的其他点也一定可以,因为它们都能到达栈顶房间。于是一直弹栈至栈顶房间能到达当前房间即可。至于如何判断是否可达,如果栈中不止一个元素,只要看打开当前房间的锁的钥匙是否在栈顶房间到当前房间之间,因为由反交换律栈顶的房间不能再向左走;否则需要找一下其能走到的最左房间,这个东西暴力查找并且查完之后记录就可以线性了(直接暴力说不定也是,因为loj上一直T一个点以为复杂度假掉了,后来发现把这段注释掉照样T……事实上是建树出了一些问题,应该设一个虚根而不是遍历森林,因为边是有向的)。

    #include<iostream> 
    #include<cstdio>
    #include<cmath>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    #define ll long long
    #define N 1000010
    char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;}
    int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
    int read()
    {
        int x=0,f=1;char c=getchar();
        while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
        while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
        return x*f;
    }
    int n,m,q,key[N],tmp[N],L[N],R[N],pos[N],stk[N],pre[N],nxt[N],top,cnt;
    struct tree
    {
        int dfn[N],size[N],p[N],cnt,t;
        struct data{int to,nxt;}edge[N<<1];
        void addedge(int x,int y){t++;edge[t].to=y,edge[t].nxt=p[x],p[x]=t;}
        void dfs(int k)
        {
            size[k]=1;dfn[k]=++cnt;
            for (int i=p[k];i;i=edge[i].nxt)
            if (!size[edge[i].to])
            {
                dfs(edge[i].to);
                size[k]+=size[edge[i].to];
            }
        }
        bool isin(int x,int y){return dfn[x]<=dfn[y]&&dfn[x]+size[x]-1>=dfn[y];}
    }a,b;
    int main()
    {
    #ifndef ONLINE_JUDGE
        freopen("bzoj5288.in","r",stdin);
        freopen("bzoj5288.out","w",stdout);
        const char LL[]="%I64d
    ";
    #else
        const char LL[]="%lld
    ";
    #endif
        n=read(),m=read(),q=read();
        for (int i=1;i<=m;i++)
        {
            int x=read(),y=read();
            key[x]=y;
        }
        for (int i=1;i<=n;i++)
        {
            int t=i;
            while (t<n&&!key[t]) t++;
            cnt++;L[cnt]=i,R[cnt]=t;
            for (int j=L[cnt];j<=R[cnt];j++) pos[j]=cnt;
            i=t;
        }
        memcpy(tmp,key,sizeof(key));
        for (int i=1;i<=n;i++) if (tmp[i]) key[pos[i]]=pos[tmp[i]];
        n=cnt;
        top=0;stk[++top]=1;a.addedge(0,1);
        for (int i=2;i<=n;i++)
        {
            if (key[i-1]>=i) top=0;
            else
            {
                while (top>1&&key[i-1]<stk[top]) top--;
                if (top==1)
                {
                    int left=stk[top];
                    while (pre[left]||(left>1&&key[left-1]<i&&key[left-1]>=left)) left=pre[left]?pre[left]:left-1;
                    if (stk[top]!=left) pre[stk[top]]=left;
                    if (key[i-1]<left) top--;
                }
            }
            if (top) a.addedge(stk[top],i);
            else a.addedge(0,i);
            stk[++top]=i;
        }
        a.dfs(0);
        top=0;stk[++top]=n;b.addedge(0,n);
        for (int i=n-1;i;i--)
        {
            if (key[i]<=i) top=0;
            else
            {
                while (top>1&&key[i]>stk[top]) top--;
                if (top==1)
                {
                    int right=stk[top];
                    while (nxt[right]||(right<n&&key[right]>i&&key[right]<=right)) right=nxt[right]?nxt[right]:right+1;
                    if (stk[top]!=right) nxt[stk[top]]=right;
                    if (key[i]>right) top--;
                }
            }
            if (top) b.addedge(stk[top],i);
            else b.addedge(0,i);
            stk[++top]=i;
        }
        b.dfs(0);
        while (q--)
        {
            int x=pos[read()],y=pos[read()];
            if (a.isin(x,y)||b.isin(x,y)) puts("YES");
            else puts("NO");
        }
        return 0;
    }
  • 相关阅读:
    UITableView的简单使用
    使用UIScrollView 实现分页功能
    UIScrollView的简单使用
    关于行和列的算法
    block的定义和使用
    plist文件的读取和NSBundle的使用
    UIView的transform属性值详解
    JavaScript _proto_、prototype原型、原型链、constructor构造器、类式继承、原型继承
    javascript 跨域问题
    【javascript知识点】javascript 额外篇
  • 原文地址:https://www.cnblogs.com/Gloid/p/10096007.html
Copyright © 2011-2022 走看看