1924: [Sdoi2010]所驼门王的宝藏
Time Limit: 5 Sec Memory Limit: 128 MB
Submit: 1285 Solved: 574
[Submit][Status][Discuss]Description
Input
第一行给出三个正整数 N, R, C。 以下 N 行,每行给出一扇传送门的信息,包含三个正整数xi, yi, Ti,表示该传送门设在位于第 xi行第yi列的藏宝宫室,类型为 Ti。Ti是一个1~3间的整数, 1表示可以传送到第 xi行任意一列的“横天门”,2表示可以传送到任意一行第 yi列的“纵寰门”,3表示可以传送到周围 8格宫室的“自由<x>门”。 保证 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 1Sample Output
9HINT
测试点编号 N R C 1 16 20 20 2 300 1,000 1,000 3 500 100,000 100,000 4 2,500 5,000 5,000 5 50,000 5,000 5,000 6 50,000 1,000,000 1,000,000 7 80,000 1,000,000 1,000,000 8 100,000 1,000,000 1,000,000 9 100,000 1,000,000 1,000,000 10 100,000 1,000,000 1,000,000
Source
题解
按照题意建好有向边, 跑一遍 $Tarjan$ 缩成 $DAG$ 之后直接 $O(n)$ $DP$ 一遍求最大值即可.
至于快速建边, 可以用 $std::set$ 维护同一行/同一列的所有节点编号, 二维 $std::map$ 维护各个节点的位置. 不过如果所有点都在同一行的话可能会$GG$
参考代码
1 #include <set> 2 #include <map> 3 #include <stack> 4 #include <vector> 5 #include <cstdio> 6 #include <cstring> 7 #include <cstdlib> 8 #include <iostream> 9 #include <algorithm> 10 11 const int MAXV=1e5+10; 12 const int MAXE=5e6; 13 14 struct Edge{ 15 int from; 16 int to; 17 Edge* next; 18 }; 19 Edge E[MAXE]; 20 Edge* head[MAXV]; 21 Edge* top=E; 22 23 struct Node{ 24 int x; 25 int y; 26 int type; 27 }; 28 Node N[MAXV]; 29 30 int v; 31 int c; 32 int r; 33 int ans; 34 int clk; 35 int scc; 36 int dp[MAXV]; 37 int dfn[MAXV]; 38 int low[MAXV]; 39 int size[MAXV]; 40 int belong[MAXV]; 41 42 bool inStack[MAXV]; 43 44 std::stack<int> s; 45 std::map< int, std::set<int> > sx,sy; 46 std::map< int, std::map<int,int> > m; 47 48 void Build(); 49 void DFS(int); 50 void Tarjan(int); 51 void SweepEdge(); 52 void Initialize(); 53 void Insert(int,int); 54 55 int main(){ 56 Initialize(); 57 Build(); 58 for(int i=1;i<=v;i++){ 59 if(dfn[i]==0) 60 Tarjan(i); 61 } 62 SweepEdge(); 63 for(int i=1;i<=v;i++){ 64 if(dp[i]==0) 65 DFS(i); 66 } 67 printf("%d ",ans); 68 return 0; 69 } 70 71 void Initialize(){ 72 scanf("%d%d%d",&v,&r,&c); 73 for(int i=1;i<=v;i++){ 74 scanf("%d%d%d",&N[i].x,&N[i].y,&N[i].type); 75 sx[N[i].x].insert(i); 76 sy[N[i].y].insert(i); 77 (m[N[i].x])[N[i].y]=i; 78 } 79 } 80 81 void DFS(int root){ 82 if(dp[root]!=0) 83 return; 84 else{ 85 dp[root]=size[root]; 86 int max=0; 87 for(Edge* i=head[root];i!=NULL;i=i->next){ 88 DFS(i->to); 89 max=std::max(max,dp[i->to]); 90 } 91 dp[root]+=max; 92 ans=std::max(dp[root],ans); 93 } 94 } 95 96 void SweepEdge(){ 97 // puts("SE"); 98 Edge* ed=top; 99 top=E; 100 memset(head,0,sizeof(head)); 101 for(Edge* i=E;i!=ed;i++){ 102 if(belong[i->from]!=belong[i->to]) 103 Insert(belong[i->from],belong[i->to]); 104 } 105 } 106 107 void Tarjan(int root){ 108 dfn[root]=low[root]=++clk; 109 inStack[root]=true; 110 s.push(root); 111 for(Edge* i=head[root];i!=NULL;i=i->next){ 112 if(dfn[i->to]==0){ 113 Tarjan(i->to); 114 low[root]=std::min(low[root],low[i->to]); 115 } 116 else if(inStack[i->to]){ 117 low[root]=std::min(low[root],dfn[i->to]); 118 } 119 } 120 if(dfn[root]==low[root]){ 121 scc++; 122 int top; 123 do{ 124 top=s.top(); 125 inStack[top]=false; 126 size[scc]++; 127 belong[top]=scc; 128 s.pop(); 129 }while(top!=root); 130 } 131 } 132 133 void Build(){ 134 for(int k=1;k<=v;k++){ 135 if(N[k].type==1){ 136 std::map< int, std::set<int> >::iterator px=sx.find(N[k].x); 137 for(std::set<int>::iterator i=(*px).second.begin();i!=(*px).second.end();++i){ 138 if(k!=*i) 139 Insert(k,*i); 140 } 141 } 142 else if(N[k].type==2){ 143 std::map< int, std::set<int> >::iterator py=sy.find(N[k].y); 144 for(std::set<int>::iterator i=(*py).second.begin();i!=(*py).second.end();++i){ 145 if(k!=*i) 146 Insert(k,*i); 147 } 148 } 149 else if(N[k].type==3){ 150 for(int dx=-1;dx<=1;dx++){ 151 for(int dy=-1;dy<=1;dy++){ 152 if(dx!=0||dy!=0){ 153 int tmp=m[N[k].x+dx][N[k].y+dy]; 154 if(tmp!=0&&tmp!=k){ 155 Insert(k,tmp); 156 } 157 } 158 } 159 } 160 } 161 } 162 } 163 164 inline void Insert(int from,int to){ 165 // printf("Insert %d to %d ",from,to); 166 top->from=from; 167 top->to=to; 168 top->next=head[from]; 169 head[from]=top++; 170 }