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