Jzoj5452【NOIP2017提高A组冲刺11.5】轰炸

战狂也在玩《魔方王国》。他只会征兵而不会建城市,因此他决定对小奇的城市进行轰炸。
小奇有n 座城市,城市之间建立了m 条有向的地下通道。战狂会发起若干轮轰炸,每轮可以轰炸任意多个城市。
每座城市里都有战狂部署的间谍,在城市遭遇轰炸时,它们会通过地下通道撤离至其它城市。非常不幸的是,在地道里无法得知其它城市是否被轰炸,如果存在两个不同的城市i,j,它们在同一轮被轰炸,并且可以通过地道从城市i 到达城市j,那么城市i 的间谍可能因为撤离到城市j 而被炸死。为了避免这一情况,战狂不会在同一轮轰炸城市i 和城市j。
你需要求出战狂最少需要多少轮可以对每座城市都进行至少一次轰炸。

此题好坑啊,隔了一天才切掉

我们好多人看错题了qwq,题目有一句诡异的话:

并且可以通过地道从城市i 到达城市j

于是我们70%的人理解成了:i,j有连边

而不是:i可以通过地道到达j

好吧看对了这题就是一个tarjan缩点+最长路dp而已。。。

嗯上来就可以写一发

#pragma GCC optimize("O3")
#pragma G++ optimize("O3")
#include<vector>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 1000010
using namespace std;
struct Edge{ int v,nt; } G[N];
int h[N],dfn[N],low[N],col[N],f[N],n,m,cnt=0;
vector<int> G2[N]; int st[N],top=0,clk=0,Col,sz[N];
inline void adj(int x,int y){ G[++cnt]=(Edge){y,h[x]}; h[x]=cnt; }
void tarjan(int x){
	dfn[x]=low[x]=++clk; 
	st[++top]=x;
	for(int v,i=h[x];i;i=G[i].nt)
		if(!dfn[v=G[i].v]){
			tarjan(v); low[x]=min(low[x],low[v]);
		} else if(!col[v]) low[x]=min(low[x],dfn[v]);
	if(low[x]==dfn[x]){
		++Col;
		do { col[st[top]]=Col; sz[Col]++; } while(st[top--]!=x);
	}
}
int dp(int x){
	if(~f[x]) return f[x]; f[x]=0;
	for(int i=0,z=G2[x].size();i<z;++i) f[x]=max(f[x],dp(G2[x][i]));
	f[x]+=sz[x]; return f[x];
}
int main(){
	freopen("bomb.in","r",stdin);
	freopen("bomb.out","w",stdout);
	scanf("%d%d",&n,&m);
	for(int x,y,i=1;i<=m;++i){
		scanf("%d%d",&x,&y);
		adj(x,y);
	} memset(f,-1,sizeof f);
	for(int i=1;i<=n;++i) if(!dfn[i]) tarjan(i);
	for(int i=1;i<=n;++i)
		for(int j=h[i];j;j=G[j].nt)
			if(col[i]!=col[G[j].v]) G2[col[i]].push_back(col[G[j].v]);
	for(int i=1;i<=n;++i) if(!~f[i]) f[0]=max(f[0],dp(i));
	printf("%d\n",*f);
}
加上了O3这也才95分!

当然啦,1BW层递归在OJ上肯定要爆栈的

于是,懒得打人工栈,就找了一些奇技淫巧:C++如何扩大

有兴趣可以点击黑块的链接看看,下面就把用汇编扩栈的code放上来

(还有几天就noip了请勿比赛中作死而且noip不卡栈)

#pragma GCC optimize("O3")
#pragma G++ optimize("O3")
#include<vector>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<algorithm>
#define N 1000010
using namespace std;
extern int main2(void) __asm__ ("main2");  
struct Edge{ int v,nt; } G[N];
int h[N],dfn[N],low[N],col[N],f[N],n,m,cnt=0;
vector<int> G2[N]; int st[N],top=0,clk=0,Col,sz[N];
inline void adj(int x,int y){ G[++cnt]=(Edge){y,h[x]}; h[x]=cnt; }

void tarjan(int x){
	dfn[x]=low[x]=++clk; 
	st[++top]=x;
	for(int v,i=h[x];i;i=G[i].nt)
		if(!dfn[v=G[i].v]){
			tarjan(v); low[x]=min(low[x],low[v]);
		} else if(!col[v]) low[x]=min(low[x],dfn[v]);
	if(low[x]==dfn[x]){
		++Col;
		do { col[st[top]]=Col; sz[Col]++; } while(st[top--]!=x);
	}
}
int dp(int x){
	if(~f[x]) return f[x]; f[x]=0;
	for(int i=0,z=G2[x].size();i<z;++i) f[x]=max(f[x],dp(G2[x][i]));
	f[x]+=sz[x]; return f[x];
}
int main2(){
	scanf("%d%d",&n,&m);
	for(int x,y,i=1;i<=m;++i){
		scanf("%d%d",&x,&y);
		adj(x,y);
	} memset(f,-1,sizeof f);
	for(int i=1;i<=n;++i) if(!dfn[i]) tarjan(i);
	for(int i=1;i<=n;++i)
		for(int j=h[i];j;j=G[j].nt)
			if(col[i]!=col[G[j].v]) G2[col[i]].push_back(col[G[j].v]);
	for(int i=1;i<=n;++i) if(!~f[i]) f[0]=max(f[0],dp(i));
	printf("%d\n",*f); exit(0);
}
int main(){
	freopen("bomb.in","r",stdin);
	freopen("bomb.out","w",stdout);
	int size = 256 << 20;  // 256Mb  
    	char *p = (char *)malloc(size) + size;  
    	__asm__ __volatile__(  
        "movq  %0, %%rsp\n"  
        "pushq $exit\n"   
        "jmp main2\n"  
        :: "r"(p)); 
}

转载于:https://www.cnblogs.com/Extended-Ash/p/7800608.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值