您的位置:首页 > 其它

【NOIP2016提高A组集训第10场11.8】时空传送

2016-11-08 22:46 330 查看

Description

经过旷久的战争,ZMiG和707逐渐培养出了深厚的感♂情。他们逃到了另一块大陆上,决定远离世间的纷争,幸福地生活在一起。钟情707的neither_nor决心要把他们拆散,他要动用手中最大杀器之一——超时空传送仪来分开ZMiG和707。ZMiG和707所在的大陆可以被描述成N个点M条边的有向无环图。707和ZMiG自带魔法防御,neither_nor只可以用超时空传送仪把707传送到一个点,再把ZMiG传送到一个能到达707所在点的点,然后为ZMiG指定一条寻找707的路径,他当然想把707和ZMiG分隔的越远越好,所以他会规划一条距离最长的路线。707自然也知道这一点,但是她没有办法阻止,她唯一能做且必须做的就是利用手中的炸药炸掉大陆上的一个点,然后与这条大陆相连的边也会自动被抹去,这样就会打乱neither_nor本来的计划。但是由于707过于敏捷,他的行动必须在neither_nor之前。换句话说,707需要先选择他炸掉哪个点,之后neither_nor一定会选择一条图中存在的最长路径来分开ZMiG和707。

707想让这条路径最短,所以她要问问你他应该炸掉哪个点。

Solution

这道题,很难,比赛的时候就是一脸懵逼的去打暴搜40分。

比赛之后,用了好久才弄懂,觉得这个想法十分的机智。

设f[i]和g[i]分别为从一个点走到i的最长路和i到另一个点的最长路(就是从S到i的最长路和i到T的最长路)

首先,在原图中,一条边的贡献就是f[a]+g+1,a和b是起点和终点。

考虑,删掉了一条边,怎样操作才不会去影响别的边的情况。

因为是有向无环图,所以我们可以考虑一下拓扑排序。

然后我们试着按拓扑序一个个的去删点,那么一开始所有点的情况(最长路)都是g[i]。

那么我们在考虑用一个堆去维护一下最长路。

那么我们现在把x删掉之前,因为已经从上面的点走下来了,那么前面的点的信息就没有用了,所以把连向x的点的信息(f[y]+g[x]+1)从堆中踢掉,然后他自己的信息(g[x])也没有用了,因为我们马上要把x踢掉了,所以把这个也从堆中踢掉。

然后,我们去一下堆首更新一下答案。

因为x没了,即将有一些新的点的信息要更新,所以把x连出去的点的信息(f[x]+g[y]+1)放进堆里面。因为虽然x断了,但是f[x]还是有用的,所以把x再放进堆里面。

c++用multiset比较好实现。

[b]Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fod(i,a,b) for(i=a;i>=b;i--)
#define rep(i,a) for(i=first[a];i;i=next[i])
#define rep1(i,a) for(i=first1[a];i;i=next1[i])
using namespace std;
const int maxn=75007;
int i,j,k,l,n,m,ans;
int first[maxn*2],last[maxn*2],next[maxn*2],chang[maxn*2],num;
int first1[maxn*2],last1[maxn*2],next1[maxn*2],chang1[maxn*2],num1;
int f[maxn*2],g[maxn*2],data[maxn*10],S,T,p[maxn*2],x,ans1,c[maxn*2];
bool bz[maxn*2];
multiset<int>t;
void add(int x,int y,int z){last[++num]=y,next[num]=first[x],first[x]=num,chang[num]=z;}
void add1(int x,int y,int z){last1[++num1]=y,next1[num1]=first1[x],first1[x]=num1,chang1[num1]=z;}
void tuopu(){
int i,head=0,tail=p[0],now;
while(head<tail){
now=p[++head];
rep(i,now){
if(c[last[i]]){
c[last[i]]--;
if(!c[last[i]])p[++tail]=last[i];
}
}
}
p[0]=tail;
}
int main(){
//  freopen("fan.in","r",stdin);
freopen("chronosphere.in","r",stdin);
freopen("chronosphere.out","w",stdout);
scanf("%d%d",&n,&m);S=0,T=n+1;
fo(i,1,m)scanf("%d%d",&k,&l),add(k,l,1),add1(l,k,1),c[l]++;
fo(i,1,n)if(!c[i])p[++p[0]]=i,c[i]=0;
tuopu();
fo(i,1,n){
rep(j,p[i]){
f[last[j]]=max(f[p[i]]+1,f[last[j]]);
}
}
fod(i,n,1){
rep1(j,p[i]){
g[last1[j]]=max(g[p[i]]+1,g[last1[j]]);
}
}
fo(i,1,n)t.insert(g[i]);
ans=0x7fffffff;
fo(j,1,n){
x=p[j];
rep1(i,x){
if(!last1[i])continue;
t.erase(t.find(f[last1[i]]+g[x]+1));
}
t.erase(t.find(g[x]));
k=*--t.end();
if(k<ans||k==ans&&x<ans1)ans=k,ans1=x;
rep(i,x){
if(last[i]==n+1)continue;
t.insert(g[last[i]]+f[x]+1);
}
t.insert(f[x]);
}
printf("%d %d\n",ans1,ans);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: