[SDOI2010]BZOJ 1924所驼门王的宝藏-强连通分量-缩点-拓扑排序-dp

121 篇文章 0 订阅
40 篇文章 0 订阅

题目链接:右转进入题目

题目大意:自行参考题目

题解:tarjan缩点后拓排一下dp乱搞即可。

代码:

//BZOJ 1924
//SDOI 2010
#include<iostream>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<algorithm>
#define MAXN 100010
#define MAXRC 1000010
using namespace std;
vector<int> vx[MAXRC],vy[MAXRC],g[MAXN],sccg[MAXN];
int n,r,c,color_cnt,belong[MAXN],w[MAXN],sz[MAXN];
int dp[MAXN],x[MAXN],y[MAXN],t[MAXN],topo[MAXN];
void add_edge(int u,int v)
{
	g[u].push_back(v);return;
}
int state[MAXN],low[MAXN],dfn[MAXN],dfs_clock;
stack<int> s;
queue<int> q;
int dfs(int x)
{
	state[x]=1;
	low[x]=dfn[x]=++dfs_clock;
	s.push(x);
	for(int i=g[x].size()-1;i>=0;i--)
		if(!state[g[x][i]])
		{
			dfs(g[x][i]);
			low[x]=min(low[x],low[g[x][i]]);
		}
		else if(state[g[x][i]]==1)
			low[x]=min(low[x],dfn[g[x][i]]);
	if(dfn[x]==low[x])
	{
		color_cnt++;
		sz[color_cnt]=0;
		while(s.top()!=x)
		{
			sz[color_cnt]++;
			belong[s.top()]=color_cnt;
			state[s.top()]=2;s.pop();
		}
		belong[s.top()]=color_cnt;
		state[s.top()]=2;s.pop();
		sz[color_cnt]++;
	}
	return 0;
}
void clears(stack<int> &s)
{
	while(!s.empty()) s.pop();
	return;
}
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]);
		vx[x[i]].push_back(i);
		vy[y[i]].push_back(i);
	}
/*	for(int i=1;i<=c;i++)
	{
		cout<<i<<"::";
		for(int j=vy[i].size()-1;j>=0;j--)
			cout<<vy[i][j]<<" ";
		cout<<endl;
	}*/
	for(int i=1;i<=n;i++)
		if(t[i]==1)
			for(int j=vx[x[i]].size()-1;j>=0;j--)
			{
				if(i!=vx[x[i]][j])
					add_edge(i,vx[x[i]][j]);
			}
		else if(t[i]==2)
			for(int j=vy[y[i]].size()-1;j>=0;j--)
			{
				if(i!=vy[y[i]][j])
					add_edge(i,vy[y[i]][j]);
			}
		else for(int j=-1;j<=1;j++)
			if(x[i]+j>=1&&x[i]+j<=r)
				for(int k=vx[x[i]+j].size()-1;k>=0;k--)
					if(abs(y[vx[x[i]+j][k]]-y[i])<=1&&vx[x[i]+j][k]!=i)
						add_edge(i,vx[x[i]+j][k]);
	clears(s);dfs_clock=color_cnt=0;
	for(int i=1;i<=n;i++)
		if(!state[i]) dfs(i);
	for(int i=1;i<=n;i++)
		for(int j=g[i].size()-1;j>=0;j--)
			if(belong[i]!=belong[g[i][j]])
			{
				sccg[belong[i]].push_back(belong[g[i][j]]);
				w[belong[g[i][j]]]++;
			}
	int scc_cnt=color_cnt;
	for(int i=1;i<=scc_cnt;i++)
		if(w[i]==0) q.push(i);
	int cnt=0,x;
	while(!q.empty())
	{
		topo[++cnt]=x=q.front();q.pop();
		for(int i=sccg[x].size()-1;i>=0;i--)
		{
			w[sccg[x][i]]--;
			if(!w[sccg[x][i]]) q.push(sccg[x][i]);
		}
	}
	int maxans=0;
	for(int i=1;i<=scc_cnt;i++)
	{
		dp[topo[i]]+=sz[topo[i]];
		if(dp[topo[i]]>maxans) maxans=dp[topo[i]];
		for(int j=sccg[topo[i]].size()-1;j>=0;j--)
			dp[sccg[topo[i]][j]]=max(dp[sccg[topo[i]][j]],dp[topo[i]]);
	}
	printf("%d\n",maxans);return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值