战狂也在玩《魔方王国》。他只会征兵而不会建城市,因此他决定对小奇的城市进行轰炸。
小奇有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));
}