hdu5195 二分+线段树+拓扑序

这题说的给了n个点m条边要求保证是一个有向无环图,可以删除至多k条边使得这个图的拓扑序的字典序最大,我们知道如果我们要排一个点的时候一定要考虑比他大的点是否可以、通过拆边马上拆出来,如果可以拆当然是拆,肯定保证字典序最大,如果不能拆,就不拆留着以后拆,当初这个比他大的点度数小于k的,最大是多少,这个方法我一直想不出,后来看了题解,二分加线段树,可以做到,线段树维护每个点的d[i],然后通过二分找出小于k的最大点是多少。

  1 #include <iostream>
  2 #include <algorithm>
  3 #include <string.h>
  4 #include <vector>
  5 #include <cstdio>
  6 #include<queue>
  7 using namespace std;
  8 const int maxn =100005;
  9 struct Edge{
 10    int u,v;
 11    Edge(int uu=0, int vv=0){
 12        u= uu; v =vv;
 13    }
 14 };
 15 vector<Edge> E;
 16 vector<int> G[maxn],REG[maxn];
 17 void add_edg(int u, int v){
 18     E.push_back(Edge(u,v));
 19     G[u].push_back(E.size()-1);
 20     REG[v].push_back(E.size()-1);
 21 }
 22 int ind[maxn];
 23 int cL, cR,cans;
 24 struct Itree{
 25     int id[maxn*4];
 26     void build(int O, int L, int R){
 27         if(L==R){
 28               id[O] = ind[L] ; return ;
 29         }
 30         int mid = ( L + R ) >> 1 ;
 31         build(O*2,L,mid);
 32         build(O*2+1,mid+1,R);
 33         id[O]=min(id[O*2],id[O*2+1]);
 34     }
 35     void update(int o, int L, int R){
 36         if(  L == R ){
 37               id[o] = cans;  return ;
 38         }
 39         int mid=(L+R)>>1;
 40         if(cL<=mid){
 41              update(o*2,L,mid);
 42         }else update(o*2+1,mid+1,R);
 43         id[o]=min(id[o*2],id[o*2+1]);
 44     }
 45     void query(int o , int L, int R){
 46         if(cL<=L && cR>=R){
 47              cans =min(cans,id[o]);return ;
 48         }
 49         int mid = (L+R)>>1;
 50         if(cL <= mid) query(o*2,L,mid);
 51         if(cR>mid) query(o*2+1,mid+1,R);
 52     }
 53 }T;
 54 bool use[maxn];
 55 void init(int n){
 56     for(int i=0; i<n; i++){
 57          G[i].clear();
 58          REG[i].clear();
 59     }
 60     E.clear();
 61     memset(ind,0,sizeof(ind));
 62     memset(use,true,sizeof(use));
 63 }
 64 int jud(int k, int n){
 65    int L=1,R=n,ans=-1;
 66    while(L<=R){
 67         int mid = (L+R)>>1;
 68         cans = k+1;
 69         cL=mid; cR=R;
 70         T.query(1,1,n);
 71         if(cans<=k){
 72              ans=mid; L=mid+1;
 73         }
 74         else R=mid-1;
 75    }
 76    return ans;
 77 }
 78 priority_queue<int> Q;
 79 void solve1(int nk,int k,int n){
 80 
 81      for(int i=0; i<REG[nk].size(); i++){
 82           use[ REG[nk][i] ] = false;
 83      }
 84      cans = k+1;
 85      cL=cR=nk;
 86      T.update(1,1,n);
 87 }
 88 void solve2(int nk,int k,int n){
 89     for(int i=0; i<G[nk].size(); i++){
 90         int numedg = G[nk][i];
 91         if(use[numedg]){
 92              use[numedg]=false;
 93              Edge q = E[numedg];
 94              ind[q.v]--;
 95              if(ind[q.v]==0){
 96                 Q.push(q.v); ind[q.v]=k+1;
 97              }
 98              cL = cR = q.v;
 99              cans =ind[q.v];
100              T.update(1,1,n);
101         }
102     }
103 }
104 int ans[maxn];
105 int main()
106 {
107      int n,m,k;
108 
109      while(scanf("%d%d%d",&n,&m,&k)==3){
110          init(n);
111          for(int i=0; i<m; i++){
112              int u,v;
113              scanf("%d%d",&u,&v);
114              add_edg(u,v);
115              ind[v]++;
116          }
117          while(!Q.empty())Q.pop();
118          for(int i =1; i<=n; i++){
119              if(ind[i]==0){
120                  Q.push(i);
121                  ind[i]=k+1;
122              }
123          }
124          T.build(1,1,n);
125          int st=0;
126          while(!Q.empty()){
127              int top = Q.top();
128              int nk = jud(k,n);
129              if(nk>top){
130                  k-=ind[nk];
131                  solve1(nk,k,n);
132                  Q.push(nk);
133              }else{
134                  Q.pop();
135                  ans[st++]=top;
136                  solve2(top,k,n);
137              }
138          }
139          for(int i=0; i<n-1; i++) printf("%d ",ans[i]);
140          printf("%d\n",ans[n-1]);
141      }
142 
143     return 0;
144 }

 

posted @ 2015-03-29 13:07  来自大山深处的菜鸟  阅读(188)  评论(0编辑  收藏  举报