HDU5195 线段树+拓扑

DZY Loves Topological Sorting

 

Problem Description
A topological sort or topological ordering of a directed graph is a linear ordering of its vertices such that for every directed edge (uv) from vertex u to vertex v , u comes before v in the ordering.
Now, DZY has a directed acyclic graph(DAG). You should find the lexicographically largest topological ordering after erasing at most k edges from the graph.
 

 

Input
The input consists several test cases. ( TestCase5 )
The first line, three integers n,m,k(1n,m105,0km) .
Each of the next m lines has two integers: u,v(uv,1u,vn) , representing a direct edge(uv) .
 

 

Output
For each test case, output the lexicographically largest topological ordering.
 

 

Sample Input
5 5 2 1 2 4 5 2 4 3 4 2 3 3 2 0 1 2 1 3
 

 

Sample Output
5 3 1 2 4 1 3 2
Hint
Case 1. Erase the edge (2->3),(4->5). And the lexicographically largest topological ordering is (5,3,1,2,4).
 
题解:因为我们要求最后的拓扑序列字典序最大,所以一定要贪心地将标号越大的点越早入队。我们定义点 ii的入度为d_idi​​。假设当前还能删去kk条边,那么我们一定会把当前还没入队的d_i\leq kdi​​k的最大的ii找出来,把它的d_idi​​条入边都删掉,然后加入拓扑序列。可以证明,这一定是最优的。

具体实现可以用线段树维护每个位置的d_idi​​,在线段树上二分可以找到当前还没入队的d_i\leq kdi​​k的最大的ii。于是时间复杂度就是\text{O}((n+m) \log n)O((n+m)logn).

///1085422276

#include<bits/stdc++.h>
using namespace std;
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std ;
typedef long long ll;
#define mem(a) memset(a,0,sizeof(a))
#define pb push_back
inline ll read()
{
    ll x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){
        if(ch=='-')f=-1;ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        x=x*10+ch-'0';ch=getchar();
    }return x*f;
}
//****************************************
const int  N=500000+50;
#define mod 1000000007
#define inf 10000007

int ind[N],head[N],t,n,m,K,vis[N];
vector<int > ans;
vector<int >G[N];
struct ss {
   int l,r,sum,index;
}tr[N*5];
struct sss {
  int to,next;
}e[N*2];
void init() {
  t=1;mem(head);mem(ind);ans.clear();mem(vis);
  for(int i=1;i<=n;i++)G[i].clear();
}
void add(int u,int v) {e[t].to=v;e[t].next=head[u];head[u]=t++;}
void build(int k,int s,int t) {
     tr[k].l=s;tr[k].r=t;
     if(s==t) {
        tr[k].sum=ind[s];
        tr[k].index=s;
        return ;
     }
     int  mid=(s+t)>>1;
     build(k<<1,s,mid);
     build(k<<1|1,mid+1,t);
     tr[k].sum=min(tr[k<<1].sum,tr[k<<1|1].sum);
}
int ask(int k,int s,int t,int c) {
    int ret;
    if(tr[k].l==tr[k].r&&tr[k].l==s) {
            return tr[k].index;
    }
    int mid=(tr[k].l+tr[k].r)>>1;
    if(tr[k<<1|1].sum<=c) {
        ret=ask(k<<1|1,mid+1,t,c);
    }
    else  {
        ret=ask(k<<1,s,mid,c);
    }
    return ret;
}
void update(int k,int x,int c) {
     if(tr[k].l==tr[k].r&&tr[k].l==x) {
        tr[k].sum+=c;
        return ;
     }
     int mid=(tr[k].l+tr[k].r)>>1;
     if(x<=mid) update(k<<1,x,c);
     else update(k<<1|1,x,c);
     tr[k].sum=min(tr[k<<1].sum,tr[k<<1|1].sum);
}
int main() {

    while(scanf("%d%d%d",&n,&m,&K)!=EOF) {
        init();int u,v,check;
        for( int i=1;i<=m;i++) {
            scanf("%d%d",&u,&v);
            ind[v]++;
            G[u].pb(v);
        }
        build(1,1,n);
        for(int i=n;i>=1;i--) {
            check=ask(1,1,n,K);
            ans.pb(check);
            K-=ind[check];
            update(1,check,inf);
            for(int j=0;j<G[check].size();j++) {
                update(1,G[check][j],-1);
                ind[G[check][j]]--;
            }
        }
        for(int i=0;i<ans.size()-1;i++) {
            printf("%d ",ans[i]);
        }
        printf("%d\n",ans[ans.size()-1]);
    }
  return 0;
}
代码

 

转载于:https://www.cnblogs.com/zxhl/p/4954311.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值