这题说的给了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 }
时间: 2024-11-08 13:10:24