1. 程式人生 > >BZOJ 1924 [Sdoi2010]所駝門王的寶藏 tarjan縮點+拓撲DP

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; }