BZOJ3832[Poi2014]Rally——权值线段树+拓扑排序

题目描述

An annual bicycle rally will soon begin in Byteburg. The bikers of Byteburg are natural long distance cyclists. Local representatives of motorcyclists, long feuding the cyclists, have decided to sabotage the event.
There are   intersections in Byteburg, connected with one way streets. Strangely enough, there are no cycles in the street network - if one can ride from intersection U to intersection V , then it is definitely impossible to get from V to U.
The rally's route will lead through Byteburg's streets. The motorcyclists plan to ride their blazing machines in the early morning of the rally day to one intersection and completely block it. The cyclists' association will then of course determine an alternative route but it could happen that this new route will be relatively short, and the cyclists will thus be unable to exhibit their remarkable endurance. Clearly, this is the motorcyclists' plan - they intend to block such an intersection that the longest route that does not pass through it is as short as possible.
 
给定一个N个点M条边的有向无环图,每条边长度都是1。
请找到一个点,使得删掉这个点后剩余的图中的最长路径最短。

输入

In the first line of the standard input, there are two integers, N and M(2<=N<=500 000,1<=M<=1 000 000), separated by a single space, that specify the number of intersections and streets in Byteburg. The intersections are numbered from   to  . The   lines that follow describe the street network: in the  -th of these lines, there are two integers, Ai, Bi(1<=Ai,Bi<=N,Ai<>Bi), separated by a single space, that signify that there is a one way street from the intersection no. Ai to the one no. Bi.
 
第一行包含两个正整数N,M(2<=N<=500 000,1<=M<=1 000 000),表示点数、边数。
接下来M行每行包含两个正整数A[i],B[i](1<=A[i],B[i]<=N,A[i]<>B[i]),表示A[i]到B[i]有一条边。

输出

The first and only line of the standard output should contain two integers separated by a single space. The first of these should be the number of the intersection that the motorcyclists should block, and the second - the maximum number of streets that the cyclists can then ride along in their rally. If there are many solutions, your program can choose one of them arbitrarily.
 
包含一行两个整数x,y,用一个空格隔开,x为要删去的点,y为删除x后图中的最长路径的长度,如果有多组解请输出任意一组。

样例输入

6 5
1 3
1 4
3 6
3 4
4 5

样例输出

1 2
 
如果不删点求最长路很好求,直接拓扑排序求出每个点为起点的最长路取max即可。
但现在要求删点,那么就按拓扑序删点,删除经过删除点的最长路,也就是删除经过删除点的入边的最长路。
需要维护出以每个点为起点和终点的最长路,那么删除经过一条边(x,y)的最长路就是end[x]+1+start[y]。
每次删除点之后取一下剩下最长路中的最大值来更新答案。再将经过删除点出边的最长路加上就好了。
删点时只要用一个支持删除、插入、求最大值的数据结构即可。
那么为什么要按拓扑序删点?
因为只有按拓扑序删除插入才能保证不会删多或者删少。
如果随便顺序删除的话,可能一个点的入边只有一条,但经过这条入边的最长路却有很多条导致删少了。
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
int n,m;
int s[500010];
int t[500010];
int sum[4000010];
int p[500010];
int cnt;
int x,y;
int in[500010];
int out[500010];
vector<int>g[500010];
vector<int>h[500010];
queue<int>q;
int ans1,ans2;
void change(int rt,int l,int r,int k,int v)
{
    if(l==r)
    {
        sum[rt]+=v;
        return ;
    }
    int mid=(l+r)>>1;
    if(k<=mid)
    {
        change(rt<<1,l,mid,k,v);
    }
    else
    {
        change(rt<<1|1,mid+1,r,k,v);
    }
    sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
int query(int rt,int l,int r)
{
    if(l==r)
    {
        return l;
    }
    int mid=(l+r)>>1;
    if(sum[rt<<1|1]>0)
    {
        return query(rt<<1|1,mid+1,r);
    }
    else
    {
        return query(rt<<1,l,mid);
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&x,&y);
        out[x]++;
        in[y]++;
        g[x].push_back(y);
        h[y].push_back(x);
    }
    for(int i=1;i<=n;i++)
    {
        if(!in[i])
        {
            q.push(i);
            p[++cnt]=i;
        }
    }
    while(!q.empty())
    {
        int now=q.front();
        q.pop();
        int len=g[now].size();
        for(int j=0;j<len;j++)
        {
            in[g[now][j]]--;
            s[g[now][j]]=max(s[g[now][j]],s[now]+1);
            if(!in[g[now][j]])
            {
                q.push(g[now][j]);
                p[++cnt]=g[now][j];
            }
        }
    }
    for(int i=1;i<=n;i++)
    {
        if(!out[i])
        {
            q.push(i);
        }
    }
    while(!q.empty())
    {
        int now=q.front();
        q.pop();
        int len=h[now].size();
        for(int j=0;j<len;j++)
        {
            out[h[now][j]]--;
            t[h[now][j]]=max(t[h[now][j]],t[now]+1);
            if(!out[h[now][j]])
            {
                q.push(h[now][j]);
            }
        }
    }
    int S=n+1;
    int T=n+2;
    for(int i=1;i<=n;i++)
    {
        g[i].push_back(T);
        g[S].push_back(i);
        h[i].push_back(S);
        h[T].push_back(i);
        change(1,0,n,t[i],1);
    }
    s[S]=-1;
    t[T]=-1;
    ans2=n+2;
    for(int i=1;i<=cnt;i++)
    {
        int now=p[i];
        int len=h[now].size();
        for(int j=0;j<len;j++)
        {
            change(1,0,n,s[h[now][j]]+1+t[now],-1);
        }
        int res=query(1,0,n);
        if(res<ans2)
        {
            ans2=res;
            ans1=now;
        }
        len=g[now].size();
        for(int j=0;j<len;j++)
        {
            change(1,0,n,s[now]+1+t[g[now][j]],1);
        }
    }
    printf("%d %d\n",ans1,ans2);
}
posted @ 2018-09-17 08:06  The_Virtuoso  阅读(256)  评论(0编辑  收藏  举报