显然不能 n 2 n^2 n2建图,考虑建图优化。
对于横天门:
由于处于同一行的横天门一定属于同一个强连通分量,所以我们在建图连边的时候,只需要对在同一行的横天门构造一个环,而处于此行内的其他宫室,只需要从这个环中的任意一点向这个宫室建图连边就好了。
纵寰门同理。
另外一个什么什么门由于范围太小可以不管。
然后就直接缩点,跑最长链即可。
#include <bits/stdc++.h>
#define Make make_pair
#define Pair pair<int,int>
#define For(I,X,Y) for(int I=(X);I<=(Y);I++)
#define Fora(I,X,Y) for(int I=(X);I<(Y);I++)
#define ForDown(I,X,Y) for(int I=(X);I>=(Y);I--)
using namespace std;
const int Inf=1e9;
const int Max=1e5+5;
bool Vis[Max];
int Q,N,M,Ans,F[Max];
int Tot,Top,Num,Bel[Max],Low[Max],Dfn[Max],Size[Max],Stack[Max];
int Dx[8]={-1,-1,-1,0,0,1,1,1};
int Dy[8]={-1,0,1,-1,1,-1,0,1};
stack<int>S;
map<Pair,int>Map;
struct Node{
int X,Y,Id,Type;
}Door[Max];
struct Graph{
int Cnt,To[Max*10],Next[Max*10],Head[Max];
void Insert(int X,int Y) {
To[++Cnt]=Y;Next[Cnt]=Head[X];Head[X]=Cnt;
}
}G1,G2;
inline int Read(){
int X=0;char CH=getchar();bool F=0;
while(CH>'9'||CH<'0'){if(CH=='-')F=1;CH=getchar();}
while(CH>='0'&&CH<='9'){X=(X<<1)+(X<<3)+CH-'0';CH=getchar();}
return F?-X:X;
}
bool Cmp1(Node P,Node Q){
if(P.X!=Q.X) return P.X<Q.X;
if(P.Type==1) return true;
if(Q.Type==1) return false;return P.Y<Q.Y;
}
bool Cmp2(Node P,Node Q){
if(P.Y!=Q.Y) return P.Y<Q.Y;
if(P.Type==2) return true;
if(Q.Type==2) return false;return P.X<Q.X;
}
void DP(int X){
Vis[X]=1;
for(int I=G2.Head[X];I;I=G2.Next[I]) {
if(!Vis[G2.To[I]]) DP(G2.To[I]);
F[X]=max(F[X],F[G2.To[I]]);
}
Ans=max(Ans,F[X]+=Size[X]);
}
void Tarjan(int X){
S.push(X);
Dfn[X]=Low[X]=++Num;
for(int I=G1.Head[X];I;I=G1.Next[I]){
int Y=G1.To[I];
if(!Dfn[Y]){
Tarjan(Y);
Low[X]=min(Low[X],Low[Y]);
} else if(!Bel[Y]){
Low[X]=min(Low[X],Dfn[Y]);
}
}
if(Dfn[X]==Low[X]){
++Tot;
while(true){
int Y=S.top();
Size[Tot]++;Bel[Y]=Tot;S.pop();
if(X==Y) break;
}
}
}
int main(){
Q=Read(),N=Read(),M=Read();
For(I,1,Q) {
Door[I].Id=I;
Door[I].X=Read();
Door[I].Y=Read();
Door[I].Type=Read();Map[Make(Door[I].X,Door[I].Y)]=I;
}
sort(Door+1,Door+1+Q,Cmp1);
int First=1,Last=1;
For(I,1,Q) {
if(Door[I].X!=Door[I+1].X) {
if(Last!=First) G1.Insert(Door[Last].Id,Door[First].Id);Last=First=I+1;
} else {
if(Door[Last].Type==1) G1.Insert(Door[Last].Id,Door[I+1].Id);
if(Door[I+1].Type==1) Last=I+1;
if(Door[First].Type!=1) Last=First=I+1;
}
}
sort(Door+1,Door+1+Q,Cmp2);
First=1,Last=1;
For(I,1,Q) {
if(Door[I].Y!=Door[I+1].Y) {
if(Last!=First) G1.Insert(Door[Last].Id,Door[First].Id);Last=First=I+1;
} else {
if(Door[Last].Type==2) G1.Insert(Door[Last].Id,Door[I+1].Id);
if(Door[I+1].Type==2) Last=I+1;
if(Door[First].Type!=2) Last=First=I+1;
}
}
For(I,1,Q) {
if(Door[I].Type==3) {
int X=Door[I].X,Y=Door[I].Y;
Fora(J,0,8) {
if(Map.count(Make(X+Dx[J],Y+Dy[J]))) {
G1.Insert(Door[I].Id,Map[Make(X+Dx[J],Y+Dy[J])]);
}
}
}
}
For(I,1,Q) if(!Dfn[I]) Tarjan(I);
For(I,1,Q) for(int J=G1.Head[I];J;J=G1.Next[J]) if(Bel[I]!=Bel[G1.To[J]]) G2.Insert(Bel[I],Bel[G1.To[J]]);
For(I,1,Tot) if(!Vis[I]) DP(I);
printf("%d",Ans);
return 0;
}