bzoj2109 航空管制

来源:互联网 发布:java文件读写 编辑:程序博客网 时间:2024/05/01 09:21

题解

这题不难想到二分答案。。
你先对大小关系建一个反图,表示如果你想知道这个点,你必须先得到那个点的状态
由于保证有解,所以这是一个拓扑图
然后你就拓扑排序地走。。
每一个点就是连向它所有点的最小值,以及自己的时间,取一个最小值值i,表示1~i它都可以选
策略,肯定是只要可以,就往后面放,正确性显然
于是我们就要找在i前面的空位
这个显然可以用一个并查集来维护
对于当前点,你还要对你二分的答案取最小值
然后不合法情况就是存在一个点没有可以放的位置
然后就可以了
于是这个做法,时间复杂度是O(nmlogn)
因为你每一次都要拓扑走一次。。
不知道有没有常数好的人能过,反正我T了,对拍发现大概是正解的两倍
然后我们继续考虑优化,我们发现,对于同一个点,无论二分答案是什么,有许多东西的状态都是固定的,就是拓扑序与他无关的
然后我们对于每一个点,可以先跑半个图,表示这些无论二分值为什么都是不会变的,然后到时候就直接从一半开始跑,这样就省时多了
时间复杂度O()

#include<cstdio>#include<iostream>#include<algorithm>#include<cstring>#include<queue>#include<cstdlib>using namespace std;const int MAX=1<<30;const int N=2005;const int M=10005;int n,m;int s[N];struct qq{    int x,y;    int last;}e[M];int num,last[N];int d[N];void init (int x,int y){    d[y]++;    num++;    e[num].x=x;e[num].y=y;    e[num].last=last[x];    last[x]=num;}int D[N];int lalal[N];//这个点在那个位置int f[N];int find (int x){    return f[x]==x?x:f[x]=find(f[x]);}int q[N];inline int read(){    int x=0,f=1;char ch=getchar();    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}    return x*f;}int Lalal[N];//一些预处理的int DD[N];//也是一些预处理的 int F[N];int st,ed;int S,T;bool check (int X,int shen)//排在这一位行不行 {    for (int u=1;u<=n;u++) f[u]=F[u],lalal[u]=Lalal[u],d[u]=DD[u];   /* for (int u=1;u<=n;u++) printf("%d ",f[u]);    printf("\n");*/    st=S;ed=T;    lalal[X]=min(shen,lalal[X]);  // printf("YES:%d\n",lalal[X]);    f[0]=0;lalal[X]=find(lalal[X]);   //  printf("NO\n");    f[lalal[X]]=lalal[X]-1;    if (lalal[X]<=0) return false;    for (int u=last[X];u!=-1;u=e[u].last)    {        int y=e[u].y;        lalal[y]=min(lalal[y],lalal[X]);        d[y]--;        if (d[y]==0)        {               f[0]=0;lalal[y]=find(lalal[y]);        //  printf("YES:%d %d %d\n",X,y,lalal[y]);            f[lalal[y]]=lalal[y]-1;            if (lalal[y]<=0) return false;            q[++ed]=y;        }    }   // printf("TYB:%d %d\n",st,ed);    while (st<=ed)    {        int x=q[st];        for (int u=last[x];u!=-1;u=e[u].last)        {            int y=e[u].y;            lalal[y]=min(lalal[y],lalal[x]);            d[y]--;            if (d[y]==0)            {                f[0]=0;lalal[y]=find(lalal[y]);                f[lalal[y]]=lalal[y]-1;                if (lalal[y]<=0) return false;                q[++ed]=y;            }        }        st++;    }    //printf("YES\n");    return true;}void prepare (int now){    for (int i=1;i<=n;i++) lalal[i]=s[i],f[i]=i;    st=1;ed=0;    for (int u=1;u<=n;u++)    {        d[u]=D[u];        if (now==u) continue;        if (d[u]==0)        {            lalal[u]=find(lalal[u]);            f[lalal[u]]=lalal[u]-1;            q[++ed]=u;        }    }    while (st<=ed)    {        int x=q[st];        if (x==now) {st++;continue;}        for (int i=last[x];i!=-1;i=e[i].last)        {            int y=e[i].y;            lalal[y]=min(lalal[y],lalal[x]);            d[y]--;            if (d[y]==0)            {                if (y!=now)                {                    f[0]=0;lalal[y]=find(lalal[y]);                    f[lalal[y]]=lalal[y]-1;                    q[++ed]=y;                }            }        }        st++;    }/*  printf("\nYES:");    for (int u=1;u<=n;u++) printf("%d ",lalal[u]);    printf("\n");*/    for (int i=1;i<=n;i++) Lalal[i]=lalal[i];    for (int i=1;i<=n;i++) DD[i]=d[i];    for (int i=1;i<=n;i++) F[i]=f[i];    S=st;T=ed;}int main(){    num=0;memset(last,-1,sizeof(last));    n=read();m=read();    for (int u=1;u<=n;u++)s[u]=read();    for (int u=1;u<=m;u++)    {        int x,y;        x=read();y=read();        init(y,x);    }    for (int u=1;u<=n;u++) DD[u]=D[u]=d[u];    for (int u=1;u<=n;u++)    {        prepare(u);        //check(1,4);        int l=1,r=s[u];        int ans;        while (l<=r)        {            int mid=(l+r)>>1;           // printf("OZY:%d %d %d\n",l,r,mid);            if (check(u,mid)) {r=mid-1;ans=mid;}            else l=mid+1;        }        printf("%d ",ans);    }    return 0;}
原创粉丝点击