题目描述:
n<=100000,R、C<=1000000
题目分析:
如果暴力连边,之后就是tarjan缩点拓扑排序求最长路。
但是暴力连边是
O
(
n
2
)
O(n^2)
O(n2)的,考虑优化。
考虑同一行的横天门所能,它们可以相互到达,所以只需要让它们连成一个环就可以了,然后让第一个横天门向这一行的非横天门连边,这样是题意的等价表达,此行的任意横天门可以到达所有非横天门,并且这样的连边数是
O
(
n
)
O(n)
O(n)的。
纵寰门同理,自由门用map存点,连接8个方向即可。
缩点之后似乎不用拓扑排序,直接按照强联通分量的编号由大到小计算就可以了。
Code:
#include<bits/stdc++.h>
#define maxn 100005
#define line(x,y) G[x].push_back(y)
using namespace std;
typedef pair<int,int> pii;
int n,R,C,t[maxn],X[maxn],Y[maxn],tx[maxn],ty[maxn],dis[maxn],deg[maxn],siz[maxn];
int dfn[maxn],low[maxn],tim,stk[maxn],top,scc[maxn],scnt;
vector<int>r[maxn][2],c[maxn][2],G[maxn],E[maxn];
map<pii,int>graph;
int dx[8]={1,1,1,-1,-1,-1,0,0},dy[8]={1,0,-1,1,0,-1,1,-1};
void tarjan(int u){
dfn[u]=low[u]=++tim,stk[++top]=u;
for(int i=G[u].size()-1,v;i>=0;i--)
if(!dfn[v=G[u][i]]) tarjan(v),low[u]=min(low[u],low[v]);
else if(!scc[v]) low[u]=min(low[u],dfn[v]);
if(dfn[u]==low[u]){
++scnt;
do siz[scc[stk[top]]=scnt]++; while(stk[top--]!=u);
}
}
int main()
{
scanf("%d%d%d",&n,&R,&C);
for(int i=1;i<=n;i++) scanf("%d%d%d",&X[i],&Y[i],&t[i]),tx[i]=X[i],ty[i]=Y[i];
sort(tx+1,tx+1+n),sort(ty+1,ty+1+n);
tx[0]=unique(tx+1,tx+1+n)-tx-1, ty[0]=unique(ty+1,ty+1+n)-ty-1;
for(int i=1;i<=n;i++){
graph[pii(X[i],Y[i])]=i;
X[i]=lower_bound(tx+1,tx+1+tx[0],X[i])-tx;
Y[i]=lower_bound(ty+1,ty+1+ty[0],Y[i])-ty;
r[X[i]][t[i]==1].push_back(i);
c[Y[i]][t[i]==2].push_back(i);
}
for(int i=1;i<=tx[0];i++) if(r[i][1].size()){
for(int j=r[i][1].size()-1;j;j--) line(r[i][1][j],r[i][1][j-1]);
if(r[i][1].size()>1) line(r[i][1][0],r[i][1].back());
for(int j=r[i][0].size()-1;j>=0;j--) line(r[i][1][0],r[i][0][j]);
}
for(int i=1;i<=ty[0];i++) if(c[i][1].size()){
for(int j=c[i][1].size()-1;j;j--) line(c[i][1][j],c[i][1][j-1]);
if(c[i][1].size()>1) line(c[i][1][0],c[i][1].back());
for(int j=c[i][0].size()-1;j>=0;j--) line(c[i][1][0],c[i][0][j]);
}
for(int i=1,z;i<=n;i++) if(t[i]==3)
for(int j=0;j<8;j++) if(z=graph[pii(tx[X[i]]+dx[j],ty[Y[i]]+dy[j])]) line(i,z);
for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i);
for(int i=1,x,y;i<=n;i++)
for(int j=G[i].size()-1;j>=0;j--) if((x=scc[i])!=(y=scc[G[i][j]]))
E[x].push_back(y),deg[y]++;
for(int i=1;i<=scnt;i++) if(!deg[i]) stk[++top]=i,dis[i]=siz[i];
while(top){
int u=stk[top--];
for(int i=E[u].size()-1,v;i>=0;i--){
v=E[u][i],dis[v]=max(dis[v],dis[u]+siz[v]);
if(!--deg[v]) stk[++top]=v;
}
}
printf("%d\n",*max_element(dis+1,dis+1+scnt));
}