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

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]iiSiiT
首先,在原图中,一条边的贡献就是f[a]+g[b]+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比较好实现。

Code

#include
#include
#include
#include
#include
#include
#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(headif(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(kxx;
        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);
}

你可能感兴趣的:(noip,贪心,最短路)