BZOJ 1562 变换序列

Posted on 2016-09-29 11:32  ziliuziliu  阅读(109)  评论(0编辑  收藏  举报

妙啊。。。。。O(N)算法。

首先每个<n的点只连两条边。那么这就是一个环套树啊。。。。。

然后找到在环上编号最小的点,向最小的方向更新答案。一个联通块确定了一对,就确定了这个联通块所有的样子。

所以两遍dfs就好了。23333333orz blutrex。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxn 10050
#define maxv 20050
#define maxe 100500
using namespace std;
int n,d[maxn],g[maxv],nume=1,deg[maxv],ret=0,ans[maxn],dis[maxv],pre[maxv];
int stack1[maxv],stack2[maxv],top=0;
struct edge
{
    int v,nxt;
}e[maxe];
bool vis[maxv],lab[maxv];
void addedge(int u,int v)
{
    e[++nume].v=v;
    e[nume].nxt=g[u];
    g[u]=nume;
}
void dfs1(int x,int fath)
{
    vis[x]=true;
    for (int i=g[x];i;i=e[i].nxt)
    {
        int v=e[i].v;
        if (vis[v])
        {
            if (v==fath)
            {
                if (i!=(pre[x]^1)) stack1[++top]=x,stack2[top]=v;
                else continue;
            }
            else if (dis[v]<dis[x]) stack1[++top]=x,stack2[top]=v;
        }
        else {dis[v]=dis[x]+1;pre[v]=i;dfs1(v,x);}
    }
}
void dfs2(int x,int type)
{
    vis[x]=true;
    for (int i=g[x];i;i=e[i].nxt)
    {
        int v=e[i].v;
        if (vis[v]) continue;
        if (!type) {ans[x]=v-n;dfs2(v,type^1);}
        else dfs2(v,type^1);
    }
}
int main()
{
    scanf("%d",&n);
    for (int i=0;i<n;i++) ans[i]=-1;
    for (int i=0;i<n;i++)
    {
        scanf("%d",&d[i]);
        addedge(i,(i+d[i])%n+n);addedge((i+d[i])%n+n,i);
        addedge(i,(i-d[i]+n)%n+n);addedge((i-d[i]+n)%n+n,i);
        deg[i]+=2;deg[(i+d[i])%n+n]++;deg[(i-d[i]+n)%n+n]++;
    }
    for (int i=0;i<2*n;i++)
        if (!vis[i]) dfs1(i,-1);
    for (int i=1;i<=top;i++)
    {
        int now=stack1[i];
        while (now!=stack2[i]) 
        {
            lab[now]=true;
            now=e[pre[now]^1].v;
        }
        lab[stack2[i]]=true;
    }
    memset(vis,false,sizeof(vis));
    for (int i=0;i<n;i++)
    {
        if (!lab[i]) continue;
        if (vis[i]) continue;
        int mn=3*n;
        for (int j=g[i];j;j=e[j].nxt)
            mn=min(mn,e[j].v);
        ans[i]=mn-n;vis[i]=true;dfs2(mn,1);
    }
    for (int i=0;i<n;i++) if (ans[i]==-1) {printf("No Answer");return 0;}
    for (int i=0;i<n-1;i++) printf("%d ",ans[i]);printf("%d",ans[n-1]);
    return 0;
}