卧薪尝胆,厚积薄发。
SDOI2010 所驼门王的宝藏
Date: Mon Sep 24 16:27:16 CST 2018 In Category: NoCategory

Description:

一个网格图中只能通过传送门移动,传送门只在一定位置存在,传送门有三种,可以横向传送,纵向传送和往他周围八个格子传送,每个传送门有宝物,可以选一个位置进一个出,问最多能拿到多少宝物。
$1\leqslant n \leqslant10^6 $

Solution:

先把能到达的建边,然后跑缩点,拓扑序倒序 $DP$ 求最长路。
但是这样建边最坏会有 $O(n^2)$ 条边,于是把同一行或同一列能互相到达的连成一个环即可。

Code:


#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<map>
#include<queue>
#include<stack>
#include<vector>
#include<cstring>
using namespace std;
int n,r,c;
#define MAXN 1000010
map<pair<int,int>,int> p;
struct door
{
int x,y,t,id;
}d[MAXN],row[MAXN],col[MAXN];
int cntr = 0,cntc = 0;
bool cmp_x(door a,door b){return (a.x == b.x ? a.y < b.y : a.x < b.x);}
bool cmp_y(door a,door b){return (a.y == b.y ? a.x < b.x : a.y < b.y);}
bool coverrow[MAXN],covercol[MAXN];
vector<int> rowpoint[MAXN],colpoint[MAXN];
int mx[8] = {-1,-1,-1,0,1,1,1,0};
int my[8] = {-1,0,1,1,1,0,-1,-1};
struct edge
{
int to,nxt;
}e[MAXN * 8];
int edgenum = 0;
int lin[MAXN] = {0};
void add(int a,int b)
{//cout << a << " " << b << endl;
++edgenum;e[edgenum].to = b;e[edgenum].nxt = lin[a];lin[a] = edgenum;
return;
}
int dfn[MAXN],low[MAXN],tot = 0;
stack<int> s;
bool v[MAXN];
int ins[MAXN],siz[MAXN],scc = 0;
void tarjan(int k)
{
dfn[k] = low[k] = ++tot;
s.push(k);v[k] = true;
for(int i = lin[k];i != 0;i = e[i].nxt)
{
if(dfn[e[i].to] == 0)
{
tarjan(e[i].to);
low[k] = min(low[k],low[e[i].to]);
}
else if(v[e[i].to])
{
low[k] = min(low[k],dfn[e[i].to]);
}
}
if(dfn[k] == low[k])
{
int t;
++scc;siz[scc] = 0;
do
{
t = s.top();s.pop();
v[t] = false;++siz[scc];
ins[t] = scc;
}while(t != k);
}
return;
}
vector<int> g[MAXN];
int ind[MAXN];
int f[MAXN];
int main()
{
scanf("%d%d%d",&n,&r,&c);
for(int i = 1;i <= n;++i)
{
scanf("%d%d%d",&d[i].x,&d[i].y,&d[i].t);
d[i].id = i;
p[make_pair(d[i].x,d[i].y)] = i;
rowpoint[d[i].x].push_back(i);
colpoint[d[i].y].push_back(i);
if(d[i].t == 1)row[++cntr] = d[i];
if(d[i].t == 2)col[++cntc] = d[i];
}
sort(row + 1,row + 1 + cntr,cmp_x);
int st;
for(int i = 1;i <= cntr;++i)
{
if(i == 1 || row[i].x != row[i - 1].x){st = row[i].id;continue;}
if(row[i].x == row[i - 1].x)add(row[i].id,row[i - 1].id);
if(i == n || row[i].x != row[i + 1].x)add(st,row[i].id);
}
sort(col + 1,col + 1 + cntc,cmp_y);
for(int i = 1;i <= cntc;++i)
{
if(i == 1 || col[i].y != col[i - 1].y){st = col[i].id;continue;}
if(col[i].y == col[i - 1].y)add(col[i].id,col[i - 1].id);
if(i == n || col[i].y != col[i + 1].y)add(st,col[i].id);
}
for(int i = 1;i <= n;++i)if(d[i].t == 3)
for(int k = 0;k < 8;++k)
if(p.find(make_pair(d[i].x + mx[k],d[i].y + my[k])) != p.end())
add(i,p[make_pair(d[i].x + mx[k],d[i].y + my[k])]);
memset(coverrow,false,sizeof(coverrow));
memset(covercol,false,sizeof(covercol));
for(int i = 1;i <= n;++i)
{
if(d[i].t == 1 && !coverrow[d[i].x])
{
coverrow[d[i].x] = true;
for(vector<int>::iterator it = rowpoint[d[i].x].begin();it != rowpoint[d[i].x].end();++it)
if(d[*it].t != 1)add(i,*it);
}
if(d[i].t == 2 && !covercol[d[i].y])
{
covercol[d[i].y] = true;
for(vector<int>::iterator it = colpoint[d[i].y].begin();it != colpoint[d[i].y].end();++it)
if(d[*it].t != 2)add(i,*it);
}
}
for(int i = 1;i <= n;++i)
if(dfn[i] == 0)tarjan(i);
for(int k = 1;k <= n;++k)
{
for(int i = lin[k];i != 0;i = e[i].nxt)
{
if(ins[k] != ins[e[i].to])
{
g[ins[e[i].to]].push_back(ins[k]);
++ind[ins[k]];
}
}
}
queue<int> q;
for(int i = 1;i <= scc;++i)f[i] = siz[i];
for(int i = 1;i <= scc;++i)
if(ind[i] == 0)q.push(i);
while(!q.empty())
{
int k = q.front();q.pop();
for(int i = 0;i < g[k].size();++i)
{
f[g[k][i]] = max(f[g[k][i]],siz[g[k][i]] + f[k]);
--ind[g[k][i]];
if(ind[g[k][i]] == 0)q.push(g[k][i]);
}
}
int ans = 0;
for(int i = 1;i <= scc;++i)ans = max(ans,f[i]);
cout << ans << endl;
return 0;
}
In tag: 图论-tarjan
Copyright © 2020 wjh15101051
ღゝ◡╹)ノ♡