BZOJ3832: [Poi2014]Rally

138 篇文章 0 订阅
77 篇文章 0 订阅

喵喵喵

新建点st连向所有点,所有点连向点ed,f[i]表示S到i的最长链,g[i]表示i到T的最长链,那么过一条边< u,v>的最长链就是f[u]+< u,v>+g[v],将这个定义为边权,那么原图任意一个割集中最大的边权就是图中的最长链
按拓扑序枚举删的点,一开始原图分成st和其他点这两个集合S,T,每次选出T中一个可拓展的点v,将割集中连向v的边删掉,剩余的最大边权就是删去v的答案,再将v加入S集,割集中加入v的出边
资瓷添加删除和询问最大值,用堆就可以了

code:

#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;

inline void read(int &x)
{
    char c;while(!((c=getchar())>='0'&&c<='9'));
    x=c-'0';
    while((c=getchar())>='0'&&c<='9') (x*=10)+=c-'0';
}
inline void up(int &x,const int &y){if(x<y)x=y;}
inline void down(int &x,const int &y){if(x>y)x=y;}
const int maxn = 1100000;
const int maxm = 2100000;

int n,m;
int e[maxm][2],cnt;
int f[maxn],g[maxn];
vector<int>V1[maxn],V2[maxn];
int ind[maxn];
queue<int>q;

struct node{int ei,x;}; bool v[maxm];
inline bool operator <(const node x,const node y){return x.x<y.x;}
priority_queue<node>Q;
void push(const int ei) { v[ei]=true; Q.push((node){ei,f[e[ei][0]]+g[e[ei][1]]}); }
void del(const int ei) { v[ei]=false; }
int Top()
{
    while(!Q.empty())
    {
        const node now=Q.top();
        if(!v[now.ei]) { Q.pop(); continue; }
        return now.x;
    }
    return n;
}

int ans,ansi;

int main()
{
    read(n); read(m); ans=n+1;
    for(int i=1;i<=m;i++)
    {
        int x,y; read(x); read(y);
        ++cnt; e[cnt][0]=x,e[cnt][1]=y;
        V1[x].push_back(cnt);
        V2[y].push_back(cnt);
    }
    for(int i=1;i<=n;i++)
    {
        ++cnt; e[cnt][0]=n+1,e[cnt][1]=i;
        V1[n+1].push_back(cnt);
        V2[i].push_back(cnt);
        ++cnt; e[cnt][0]=i,e[cnt][1]=n+2;
        V1[i].push_back(cnt);
        V2[n+2].push_back(cnt);
    }n+=2;

    for(int i=1;i<=n;i++) for(int j=0;j<V1[i].size();j++)
        ind[e[V1[i][j]][1]]++;
    q.push(n-1); f[n-1]=0;
    while(!q.empty())
    {
        const int x=q.front(); q.pop();
        for(int i=0;i<V1[x].size();i++)
        {
            int y=e[V1[x][i]][1]; up(f[y],f[x]+1);
            ind[y]--; if(!ind[y]) q.push(y);
        }
    }

    for(int i=1;i<=n;i++) for(int j=0;j<V2[i].size();j++)
        ind[e[V2[i][j]][0]]++;
    q.push(n); g[n]=0;
    while(!q.empty())
    {
        const int x=q.front(); q.pop();
        for(int i=0;i<V2[x].size();i++)
        {
            int y=e[V2[x][i]][0]; up(g[y],g[x]+1);
            ind[y]--; if(!ind[y]) q.push(y);
        }
    }

    for(int i=1;i<=n;i++) for(int j=0;j<V1[i].size();j++) 
        ind[e[V1[i][j]][1]]++;
    q.push(n-1);
    while(!q.empty())
    {
        const int x=q.front(); q.pop();
        for(int i=0;i<V2[x].size();i++) del(V2[x][i]);
        int tmp=Top();
        if(ans>tmp) ansi=x,ans=tmp;
        for(int i=0;i<V1[x].size();i++)
        {
            int ei=V1[x][i],y=e[ei][1];
            ind[y]--; if(!ind[y]) q.push(y);
            push(ei);
        }
    }
    printf("%d %d\n",ansi,ans-1);

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值