BZOJ1924:[SDOI2010]所驼门王的宝藏(强连通分量,拓扑排序)

Description

Input

第一行给出三个正整数 N, R, C。 以下 N 行,每行给出一扇传送门的信息,包含三个正整数xi, yi, Ti,表示该传送门设在位于第 xi行第yi列的藏宝宫室,类型为 Ti。Ti是一个1~3间的整数, 1表示可以传送到第 xi行任意一列的“横天门”,2表示可以传送到任意一行第 yi列的“纵寰门”,3表示可以传送到周围 8格宫室的“八方门”。 保证 1≤xi≤R,1≤yi≤C,所有的传送门位置互不相同。

Output

只有一个正整数,表示你确定的路线所经过不同藏宝宫室的最大数目。

Sample Input

10 7 7
2 2 1
2 4 2
1 7 2
2 7 3
4 2 2
4 4 1
6 7 3
7 7 1
7 5 2
5 2 1

Sample Output

9

HINT

N<=100000, R<=100000, C<=100000

Solution 

一开始的正解的想法让我以为边数太多然后叉掉了……其实是可以过的……

很容易可以想到做法就是门和门之间连边,然后tarjan缩个点再拓扑排序跑个最长路就完事了。不过直接连边$n^2$肯定会GG。

对于同一行的门来说,横门间显然可以相互传送,只需要选定一个横门,然后向这一行的其他横门连双向边,向这一行的其他门连单向边,这样就可以保证缩点后横门在一个强连通分量里了。列同理。

Code

  1 #include<iostream>
  2 #include<cstring>
  3 #include<cstdio>
  4 #include<vector>
  5 #include<queue>
  6 #include<map>
  7 #define N (100009)
  8 using namespace std;
  9 
 10 struct Node{int x,y,t,id;}a[N];
 11 struct Edge{int to,next;}edge[N*10];
 12 int n,m,r,c,e1[N*3],e2[N*10],Ind[N],dp[N];
 13 int head[N],num_edge;
 14 int Dfn[N],Low[N],stack[N],ID[N],Num[N];
 15 int top,id_num,dfs_num;
 16 int dx[10]={0,0,0,1,1,1,-1,-1,-1},dy[10]={0,1,-1,0,1,-1,0,1,-1};
 17 vector<int>Line[N*10],List[N*10];
 18 map<int,int>Map[N*10];
 19 queue<int>q;
 20 bool vis[N];
 21 
 22 void add(int u,int v)
 23 {
 24     edge[++num_edge].to=v;
 25     edge[num_edge].next=head[u];
 26     head[u]=num_edge;
 27     if (!m) e1[num_edge]=u,e2[num_edge]=v;
 28 }
 29 
 30 void Tarjan(int x)
 31 {
 32     Dfn[x]=Low[x]=++dfs_num;
 33     stack[++top]=x; vis[x]=true;
 34     for (int i=head[x]; i; i=edge[i].next)
 35         if (!Dfn[edge[i].to])
 36             Tarjan(edge[i].to),Low[x]=min(Low[x],Low[edge[i].to]); 
 37         else if (vis[edge[i].to])
 38             Low[x]=min(Low[x],Dfn[edge[i].to]);
 39     if (Low[x]==Dfn[x])
 40     {
 41         vis[x]=false; ID[x]=++id_num; Num[id_num]++;
 42         while (stack[top]!=x)
 43         {
 44             vis[stack[top]]=false;
 45             Num[id_num]++;
 46             ID[stack[top--]]=id_num;
 47         }
 48         top--;
 49     }
 50 }
 51 
 52 void Add()
 53 {
 54     for (int i=1; i<=r; ++i)
 55     {
 56         int x=0,sz=Line[i].size();
 57         for (int j=0; j<sz; ++j)
 58             if (a[Line[i][j]].t==1){x=Line[i][j]; break;}
 59         if (!x) continue;
 60         for (int j=0; j<sz; ++j)
 61             if (Line[i][j]!=x)
 62             {
 63                 add(x,Line[i][j]);
 64                 if (a[Line[i][j]].t==1) add(Line[i][j],x);
 65             }
 66     }
 67     for (int i=1; i<=c; ++i)
 68     {
 69         int x=0,sz=List[i].size();
 70         for (int j=0; j<sz; ++j)
 71             if (a[List[i][j]].t==2){x=List[i][j]; break;}
 72         if (!x) continue;
 73         for (int j=0; j<sz; ++j)
 74             if (List[i][j]!=x)
 75             {
 76                 add(x,List[i][j]);
 77                 if (a[List[i][j]].t==2) add(List[i][j],x);
 78             }
 79     }
 80     for (int i=1; i<=n; ++i)
 81         if (a[i].t==3)
 82         {
 83             int x=a[i].x,y=a[i].y;
 84             for (int j=1; j<=8; ++j)
 85             {
 86                 int t=Map[x+dx[j]][y+dy[j]];
 87                 if (t) add(i,t);
 88             }
 89         }
 90 }
 91 
 92 void Toposort()
 93 {
 94     int ans=0;
 95     for (int i=1; i<=id_num; ++i) ans=max(ans,Num[i]);
 96     for (int i=1; i<=id_num; ++i) if (!Ind[i]) q.push(i),dp[i]=Num[i];
 97     while (!q.empty())
 98     {
 99         int x=q.front(); q.pop();
100         for (int i=head[x]; i; i=edge[i].next)
101         {
102             int y=edge[i].to; Ind[y]--;
103             if(!Ind[y]) q.push(y);
104             dp[y]=max(dp[y],dp[x]+Num[y]);
105             ans=max(ans,dp[y]);
106         }
107     }
108     printf("%d\n",ans);
109 }
110 
111 int main()
112 {
113     scanf("%d%d%d",&n,&r,&c);
114     for (int i=1; i<=n; ++i)
115     {
116         scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].t);
117         Line[a[i].x].push_back(i);
118         List[a[i].y].push_back(i);
119         Map[a[i].x][a[i].y]=i;
120     }
121     Add();
122     for (int i=1; i<=n; ++i)
123         if (!Dfn[i]) Tarjan(i);
124     
125     memset(head,0,sizeof(head));
126     m=num_edge; num_edge=0;
127     for (int i=1; i<=m; ++i)
128         if (ID[e1[i]]!=ID[e2[i]])
129             add(ID[e1[i]],ID[e2[i]]),Ind[ID[e2[i]]]++;
130     Toposort();
131 }
posted @ 2018-09-09 19:34  Refun  阅读(179)  评论(0编辑  收藏  举报