YBTOJ I. 5.宫室宝藏

 思路:缩点+拓扑dp

难点:建图,如果每一行全是横门或每一列全为纵门那就需要O(n^2)来建图,直接炸

那么我们不难找到性质:每一行的横门的集合为强连通分量,每一列的纵门的集合为强连通分量

那么将每一行(列)的强连通分量连为一个环即可

建边时可以先排序将横门放前,在将纵门放前,至于第三种门,直接建边即可

注意:建第三种边时我们应判断其四周是否有宝藏宫室,但是开不了int数组来存编号,于是干脆就将整个有编号的点存入哈希表中,找的时候就去搜那个点的哈希值所对应的编号是否为0,如果不为0,建边!!

剩下的就是跑一遍Tarjan缩点重新建图,再走一遍简单的拓扑dp即可

Code

#include<bits/stdc++.h>
#define re register
#define int long long
#define inl inline
using namespace std;
int read(){
	int sum=0,f=1;char c=getchar();
	while(!isdigit(c)){if(c=='-') f=-1;c=getchar();}
	while(isdigit(c)){sum=(sum<<3)+(sum<<1)+(c^48);c=getchar();}
	return sum*f;
}
const int mod=1e4+7;
const int N=1e7+10;
int n,m,x;
int cnt,top,dep,color;
int head[N],head2[N],stk[N],dis[N],dfn[N],low[N],siz[N],col[N],sum;
int ind[N];
std::queue<int> topu;
int dx[]={-1,0,1,0,1,1,-1,-1};
int dy[]={1,1,1,-1,0,-1,0,-1};
struct node{
	int to,nxt;
}e[N<<1],r[N<<1];
struct Node{
	int a,b,c,id;
}typ[N<<1];
map<int,int> mp;
bool cmp1(Node x,Node y){
	if(x.a!=y.a) return x.a<y.a;
	if(x.c==1) return 1;
	if(y.c==1) return 0;
	return x.b<y.b;
}
bool cmp2(Node x,Node y){
	if(x.b!=y.b) return x.b<y.b;
	if(x.c==2) return 1;
	if(y.c==2) return 0;
	return x.a<y.a; 
}
void add(int x,int y){
	e[++cnt].to=y;
	e[cnt].nxt=head[x];
	head[x]=cnt;
}
void add2(int x,int y){
	r[++cnt].to=y;
	r[cnt].nxt=head2[x];
	head2[x]=cnt;
}
void tarjan(int u){
	dfn[u]=low[u]=++dep;stk[++top]=u;
	for(int i=head[u];i;i=e[i].nxt){
		int v=e[i].to;
		if(!dfn[v]){
			tarjan(v);
			low[u]=min(low[u],low[v]);
		}
		else if(!col[v]){
			low[u]=min(low[u],dfn[v]);
		}
	}
	if(low[u]==dfn[u]){
		color++;
		col[u]=color;
		siz[color]++;
		while(stk[top]!=u){
			siz[color]++;
			col[stk[top--]]=color;
		}
		top--;
	}
}
signed main(){
	x=read(),n=read(),m=read();
	for(int i=1;i<=x;i++){
		typ[i].a=read();
		typ[i].b=read();
		typ[i].c=read();
		typ[i].id=i;
		mp[(typ[i].a-1)*m+typ[i].b]=typ[i].id;
	}
	//Hash();
	sort(typ+1,typ+1+x,cmp1);
	for(int i=1;i<=x;i++){
		if(typ[i].c==1){
			int fina=0;
			int fi,la=0;
			for(int j=i;j<=x&&typ[i].a==typ[j].a;j++){
				fina=j;
				if(typ[i].c==typ[j].c){
					if(!la){
						la=typ[j].id;
						fi=la;
						continue;
					}
					add(la,typ[j].id);
					la=typ[j].id;
				}
				else add(typ[i].id,typ[j].id);
			}
			if(la!=fi){
				add(la,fi);
			}
			i=fina;
		}
	}
	sort(typ+1,typ+1+x,cmp2);
	for(int i=1;i<=x;i++){
		if(typ[i].c==2){
			int fina=0;
			int fi,la=0;
			for(int j=i;j<=x&&typ[i].b==typ[j].b;j++){
				fina=j;
				if(typ[i].c==typ[j].c){
					if(!la){
						la=typ[j].id;
						fi=la;
						continue;
					}
					add(la,typ[j].id);
					la=typ[j].id;
				}
				else add(typ[i].id,typ[j].id);
			}
			if(la!=fi){
				add(la,fi);
			}
			i=fina;
		}
	}
	for(int i=1;i<=x;i++){
		if(typ[i].c!=3) continue;
		for(int j=0;j<8;j++){
			int xx=typ[i].a+dx[j];
			int yy=typ[i].b+dy[j];
			int p=mp[(xx-1)*m+yy];
			if(!p) continue;
			add(typ[i].id,p);
		}
	}
	for(int i=1;i<=x;i++) if(!dfn[i]) tarjan(i);
	cnt=0;
	for(int i=1;i<=x;i++){
		for(int j=head[i];j;j=e[j].nxt){
			int v=e[j].to;
			if(col[i]!=col[v]){
				ind[col[v]]++;
				add2(col[i],col[v]);
			}
		}
	}
	int ans=0;
	for(int i=1;i<=color;i++){
		if(!ind[i]) topu.push(i),dis[i]=siz[i],ans=max(ans,siz[i]);
	}
	while(topu.size()){
		int u=topu.front();topu.pop();
		for(int i=head2[u];i;i=r[i].nxt){
			int v=r[i].to;
			dis[v]=max(dis[v],dis[u]+siz[v]);
			ans=max(ans,dis[v]);
			ind[v]--;
			if(!ind[v]) topu.push(v);
		}
	}
	printf("%d\n",ans);
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值