zoukankan      html  css  js  c++  java
  • Luogu1155 NOIP2008双栈排序(并查集)

      两个位置i和j上的元素不能被放进同一个栈的充要条件显然是存在k使i<j<k且ak<ai<aj。由此在保证合法的情况下贪心地放就是正确的了。

      至于如何判断,可以记一下后缀最小值,每找到一对就利用补集并查集合并。放的时候要求与该栈所有元素不排斥且与另一个栈的元素不存在强制同栈的关系。

      怎么感觉远古时代noip都这么困难啊。没救了。

    #include<iostream> 
    #include<cstdio>
    #include<cmath>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    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;
    }
    #define N 1010
    int n,a[N],mn[N],fa[N<<1],stk1[N],stk2[N],top1=0,top2=0,tot=0,cur=0;
    char ans[N<<1];
    int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
    void merge(int x,int y){fa[find(x+n)]=find(y),fa[find(y+n)]=find(x);}
    int main()
    {
    #ifndef ONLINE_JUDGE
        freopen("stack.in","r",stdin);
        freopen("stack.out","w",stdout);
        const char LL[]="%I64d
    ";
    #else
        const char LL[]="%lld
    ";
    #endif
        n=read();
        for (int i=1;i<=n;i++) a[i]=read();
        mn[n+1]=n+1;for (int i=n;i;i--) mn[i]=min(a[i],mn[i+1]);
        for (int i=1;i<=n+n;i++) fa[i]=i;
        for (int i=1;i<=n;i++)
            for (int j=i+1;j<=n;j++)
            if (a[i]<a[j]&&mn[j+1]<a[i]) merge(i,j);
        for (int i=1;i<=n;i++)
        {
            while (a[stk1[top1]]==cur+1) cur++,ans[++tot]='b',top1--;
            bool flag=1;
            for (int j=1;j<=top1;j++) if (find(stk1[j]+n)==find(i)) {flag=0;break;}
            for (int j=1;j<=top2;j++) if (find(stk2[j])==find(i)) {flag=0;break;}
            if (flag) stk1[++top1]=i,ans[++tot]='a';
            else
            {
                while (a[stk1[top1]]==cur+1||a[stk2[top2]]==cur+1)
                if (a[stk1[top1]]==cur+1) cur++,ans[++tot]='b',top1--;
                else cur++,ans[++tot]='d',top2--;
                flag=1;
                for (int j=1;j<=top1;j++) if (find(stk1[j])==find(i)) {flag=0;break;}
                for (int j=1;j<=top2;j++) if (find(stk2[j]+n)==find(i)) {flag=0;break;}
                if (flag) stk2[++top2]=i,ans[++tot]='c';
                else {cout<<0;return 0;}
            }
        }
        while (top1||top2)
        if (top1&&a[stk1[top1]]<a[stk2[top2]]||top2==0) ans[++tot]='b',top1--;
        else ans[++tot]='d',top2--;
        for (int i=1;i<=tot;i++) cout<<ans[i]<<' ';
        return 0;
    }
  • 相关阅读:
    CDB命令方式创建和删除
    cdb和pdb的启停
    python 读取blob
    c# 读取blob数据
    python 为什么没有自增自减符
    程序异常重启代码
    便捷辅助开发工具
    正则表达式带例子详解
    名语中看代码
    c# 画一个报告
  • 原文地址:https://www.cnblogs.com/Gloid/p/9795685.html
Copyright © 2011-2022 走看看