zoukankan      html  css  js  c++  java
  • P3573 [POI2014]RAJ-Rally

    Problem

    给一个(n)个点,(m)条边的DAG,找到一个点,使得删去这个点后的最长路径最短。
    (2 le n le 500000,1 le m le 1000000)

    Solution

    看到DAG就想到拓扑。
    求出以(x)为起点的最长路径长度(ds_x)和以(x)为终点的最长路径长度(dt_x)。可以通过跑正反图拓扑实现。
    设第(x)个点的拓扑序为(TX_x)
    对于一条边(u o v),经过它的最长路径长度为(dt_u + ds_v + 1),正确性显然。
    考虑枚举删的点,假设我们现在删除(x),我们假设所有(TX_i < TX_x)的点放在集合(A)(TX_i > TX_x)的放在集合(B)(x)在中间。
    此时的最长路径分三种:(A o A,A o B,B o B)

    • (A o A)(max_{i in A} {dt_i})
    • (A o B)(max_{(u,v) in E,u in A,v in B} {dt_u +ds_v + 1 })
    • (B o B)(max_{i in B} {ds_i})

    (x)原来在(B)集合,现在不在(B)集合,则删除(ds_x)
    (x)在反图中连接的点都存在第二种情况,删除。

    下一次删除前,(x)(A)集合,则加入(dt_x)
    (x)在图中连接的点都存在第二种情况,加入。

    发现需要维护一个支持删除加入,求最值的东西,那么可以使用平衡树权值线段树。(其实multiset应该可以,但是我不会用)

    # include<bits/stdc++.h>
    using namespace std;
    const int N = 500005,M = 1000005;
    int n,m;
    vector <int> g[N],g2[N];
    int ds[N],dt[N];
    int du[N],du2[N];
    int Tx[N],Txtot = 0;
    int q[N];
    void topsort(void) //dt
    {
        queue <int> q;
        for(int i = 1; i <= n; i++)
        {
            if(du[i] == 0)
            {
                q.push(i);
                Tx[i] = ++Txtot;
            }
        }
        while(!q.empty())
        {
            int x = q.front(); q.pop();
            for(int i = 0; i < (int)g[x].size(); i++)
            {
                int v = g[x][i];
                dt[v] = max(dt[v],dt[x] + 1);
                if(--du[v] == 0) q.push(v),Tx[v] = ++Txtot;
            }
        }
        return;
    }
    void topsort2(void)
    {
        queue <int> q;
        for(int i = 1; i <= n; i++)
        {
            if(du2[i] == 0)
            {
                q.push(i);
            }
        }
        while(!q.empty())
        {
            int x = q.front(); q.pop();
            for(int i = 0; i < g2[x].size(); i++)
            {
                int v = g2[x][i];
                ds[v] = max(ds[v],ds[x] + 1);
                if(--du2[v] == 0) q.push(v);
            }
        }
        return;
    }
    bool compare(const int &x,const int &y)
    {
        return Tx[x] < Tx[y];
    }
    struct node
    {
        int val,l,r;
    }T[N << 2];
    int tot = 1;
    void build(int root,int l,int r)
    {
        if(l == r) {T[root].val = 0,T[root].l = T[root].r = 0; return;}
        int mid = (l + r) >> 1;
        T[root].l = ++tot,T[root].r = ++tot;
        build(T[root].l,l,mid),build(T[root].r,mid + 1,r);
        return;
    }
    void update(int root,int l,int r,int x,int d)
    {
        if(l == r && l == x)
        {
            T[root].val += d;
            return;
        }
        int mid = (l + r) >> 1;
        if(l <= x && x <= mid) update(T[root].l,l,mid,x,d);
        else if(x > mid) update(T[root].r,mid + 1,r,x,d);
        T[root].val = T[T[root].l].val + T[T[root].r].val;
        return;
    }
    int query(int root,int l,int r)
    {
        if(l == r) return l;
        int mid = (l + r) >> 1;
        if(T[T[root].r].val > 0) return query(T[root].r,mid + 1,r);
        else return query(T[root].l,l,mid);
    }
    int main(void)
    {
        scanf("%d%d",&n,&m);
        for(int i = 1; i <= m; i++)
        {
            int a,b; scanf("%d%d",&a,&b);
            g[a].push_back(b),g2[b].push_back(a);
            ++du[b],++du2[a];
        }
        topsort(),topsort2();
        build(1,1,2 * n);
        for(int i = 1; i <= n; i++)
        {
            update(1,1,2 * n,ds[i],1); q[i] = i;
        }
        sort(q + 1, q + n + 1, compare);
        int ans = 1e9 + 7,id = 0;
        for(int i = 1; i <= n; i++) // delete i
        {
            update(1,1,2 * n,ds[q[i]],-1);
            for(int j = 0; j < (int)g2[q[i]].size(); j++)
            {
                int v = g2[q[i]][j];
                update(1,1,2 * n,dt[v] + 1 + ds[q[i]],-1);
            }
            // printf("i = %d,max = %d
    ",i,Max);
            int Max = query(1,1,2 * n);
            // printf("i = %d,Max = %d
    ",i,Max);
            if(Max < ans) 
            {
                ans = Max,id = q[i];
            }
            // S.insert(dt[i]);
            update(1,1,2 * n,dt[q[i]],1);
            for(int j = 0; j < (int)g[q[i]].size(); j++)
            {
                int v = g[q[i]][j];
                update(1,1,2 * n,dt[q[i]] + 1 + ds[v],1);
            }
        }
        printf("%d %d
    ",id,ans);
        return 0;
    }
    
  • 相关阅读:
    android 生命周期图
    c++中 箭头> 双冒号:: 点号.操作符区别
    Blocks 笔记
    使用AVAudioRecorder 录音
    音频输入大小变化图
    【Linux】本机与服务器文件互传、Linux服务器文件上传下载
    【Oracle】Oracle解锁、Oracle锁表处理
    使用three.js创建3D机房模型分享一
    WPF下递归生成树形数据绑定到TreeView上
    (转载)C++抽象工厂模式(大话设计模式)
  • 原文地址:https://www.cnblogs.com/luyiming123blog/p/15142778.html
Copyright © 2011-2022 走看看