BZOJ 1924 [Sdoi2010]所駝門王的寶藏 tarjan縮點+拓撲DP

題意:
一個r*c的圖中,有n個宮殿。
每個宮殿有一個類型。
類型1:可以到達他所在的行的任意宮殿。
類型2:可以到達他所在的列的任意宮殿。
類型3:可以到達他四周八個格子的任意宮殿。
現在你從任意一個宮殿開始,詢問你最多訪問多少個宮殿。
解析:
填坑計劃。
這題建邊好麻煩=-=
首先先建出來從哪個宮殿可以到哪個宮殿的圖。
之後我們發現對於一個強連通分量來說,如果訪問了一個點,那麼即可以訪問該強連通分量中的所有點。
所以我們可以tarjan縮一下點,然後重新建圖。
然後我們發現重新建出來的圖是個DAG。
(不知道當年哪個2b說是一棵樹?)
所以我們可以在這個DAG上拓撲DP,f[i]表示從某點出發到i最多走多少點權和(點的點權爲強連通分量中的原來的點的個數)。
代碼:

#include <map>
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 100001
using namespace std;
typedef long long ll;
ll n,r,c;
int xx[]={0,1,0,-1,-1,-1,0,1,1};
int yy[]={0,1,1,1,0,-1,-1,-1,0};
int head[N],head2[N],head3[N],head4[N];
int cnt,cnt2,cnt3,cnt4;
struct node
{
    int to,next;
}linkx[N*10],linky[N*10],newedge[N*10];
struct node2
{
    int from,to,next;
}edge[N*40];
struct Point
{
    int x,y,type;
    Point(){}
    Point(int _x,int _y):x(_x),y(_y){}
    friend istream& operator >> (istream &_, Point &a)
    {scanf("%d%d%d",&a.x,&a.y,&a.type);return _;}
    friend bool operator < (Point a,Point b)
    {
        if(a.x==b.x)return a.y<b.y;
        return a.x<b.x;
    }
}pt[N];
map<ll,int>ma;
map<Point,int>ma2;
void init()
{
    memset(head2,-1,sizeof(head2));
    memset(head,-1,sizeof(head));
    cnt=1,cnt2=1;
}
void init2()
{
    memset(head3,-1,sizeof(head3));
    cnt3=1;
}
void init3()
{
    memset(head4,-1,sizeof(head4));
    cnt4=1;
}
void edgeadd(int from,int to,int *head,node *edge,int &cnt)
{
    edge[cnt].to=to,edge[cnt].next=head[from];
    head[from]=cnt++;
}
void edgeadd2(int from,int to,int *head,node2 *edge,int &cnt)
{
    edge[cnt].from=from,edge[cnt].to=to,edge[cnt].next=head[from];
    head[from]=cnt++;
}
bool ins[N];
int deep[N],low[N],sta[N],top,tot;
int belong[N],num[N],cnt_block;
void tarjan(int now,int ff)
{
    deep[now]=low[now]=++tot;
    sta[++top]=now,ins[now]=1;
    for(int i=head3[now];i!=-1;i=edge[i].next)
    {
        int to=edge[i].to;
        if(!deep[to])
        {
            tarjan(to,now);
            low[now]=min(low[now],low[to]);
        }else if(ins[to])low[now]=min(low[now],deep[to]);
    }
    if(deep[now]==low[now])
    {
        cnt_block++;
        int t=-1;
        do
        {
            t=sta[top--];
            ins[t]=0;
            belong[t]=cnt_block;
            num[cnt_block]++;
        }while(t!=now);
    }
}
int in[N];
int f[N];
void topsort()
{
    queue<int>q;
    memset(f,-0x3f,sizeof(f));
    for(int i=1;i<=cnt_block;i++)
        if(!in[i])q.push(i),f[i]=num[i];
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        for(int i=head4[u];i!=-1;i=newedge[i].next)
        {
            int to=newedge[i].to;
            f[to]=max(f[to],f[u]+num[to]);
            in[to]--;
            if(in[to]==0)
                q.push(to);
        }
    }
}
int main()
{
    #ifndef ONLINE_JUDGE
        freopen("sotomon8.in","r",stdin);
        freopen("test.out","w",stdout);
    #endif
        init(),init2();
        scanf("%lld%lld%lld",&n,&r,&c);
        for(int i=1;i<=n;i++)
        {
            cin>>pt[i],ma[(ll)(pt[i].x-1)*c+pt[i].y]=i;
            edgeadd(pt[i].x,i,head,linkx,cnt);
            edgeadd(pt[i].y,i,head2,linky,cnt2);
        }
        for(int i=1;i<=n;i++)
        {
            if(pt[i].type==1)
            {
                for(int j=head[pt[i].x];j!=-1;j=linkx[j].next)
                {   
                    int to=linkx[j].to;
                    if(to==i)continue;
                    edgeadd2(i,to,head3,edge,cnt3);
                }
            }else if(pt[i].type==2)
            {
                for(int j=head2[pt[i].y];j!=-1;j=linky[j].next)
                {
                    int to=linky[j].to;
                    if(to==i)continue;
                    edgeadd2(i,to,head3,edge,cnt3);
                }
            }else
            {
                for(int j=1;j<=8;j++)
                {
                    ll tmpx=pt[i].x+xx[j],tmpy=pt[i].y+yy[j];
                    int no=ma[(ll)(tmpx-1)*c+tmpy];
                    if(no!=0)
                        edgeadd2(i,no,head3,edge,cnt3);
                }
            }
        }
        for(int i=1;i<=n;i++)
            if(!deep[i])tarjan(i,0);
        init3();
        for(int i=1;i<cnt3;i++)
        {
            int x=edge[i].from,y=edge[i].to;
            if(belong[x]!=belong[y]&&!ma2[Point(belong[x],belong[y])])
                ma2[Point(belong[x],belong[y])]=1,edgeadd(belong[x],belong[y],head4,newedge,cnt4),in[belong[y]]++;
        }
        topsort();
        int ans=0;
        for(int i=1;i<=cnt_block;i++)
            ans=max(ans,f[i]);
        printf("%d\n",ans);
    #ifndef ONLINE_JUDGE
        fclose(stdin);fclose(stdout);
    #endif
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章