hdu5195 二分+线段树+拓扑序

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

 #include <iostream>
#include <algorithm>
#include <string.h>
#include <vector>
#include <cstdio>
#include<queue>
using namespace std;
const int maxn =;
struct Edge{
int u,v;
Edge(int uu=, int vv=){
u= uu; v =vv;
}
};
vector<Edge> E;
vector<int> G[maxn],REG[maxn];
void add_edg(int u, int v){
E.push_back(Edge(u,v));
G[u].push_back(E.size()-);
REG[v].push_back(E.size()-);
}
int ind[maxn];
int cL, cR,cans;
struct Itree{
int id[maxn*];
void build(int O, int L, int R){
if(L==R){
id[O] = ind[L] ; return ;
}
int mid = ( L + R ) >> ;
build(O*,L,mid);
build(O*+,mid+,R);
id[O]=min(id[O*],id[O*+]);
}
void update(int o, int L, int R){
if( L == R ){
id[o] = cans; return ;
}
int mid=(L+R)>>;
if(cL<=mid){
update(o*,L,mid);
}else update(o*+,mid+,R);
id[o]=min(id[o*],id[o*+]);
}
void query(int o , int L, int R){
if(cL<=L && cR>=R){
cans =min(cans,id[o]);return ;
}
int mid = (L+R)>>;
if(cL <= mid) query(o*,L,mid);
if(cR>mid) query(o*+,mid+,R);
}
}T;
bool use[maxn];
void init(int n){
for(int i=; i<n; i++){
G[i].clear();
REG[i].clear();
}
E.clear();
memset(ind,,sizeof(ind));
memset(use,true,sizeof(use));
}
int jud(int k, int n){
int L=,R=n,ans=-;
while(L<=R){
int mid = (L+R)>>;
cans = k+;
cL=mid; cR=R;
T.query(,,n);
if(cans<=k){
ans=mid; L=mid+;
}
else R=mid-;
}
return ans;
}
priority_queue<int> Q;
void solve1(int nk,int k,int n){ for(int i=; i<REG[nk].size(); i++){
use[ REG[nk][i] ] = false;
}
cans = k+;
cL=cR=nk;
T.update(,,n);
}
void solve2(int nk,int k,int n){
for(int i=; i<G[nk].size(); i++){
int numedg = G[nk][i];
if(use[numedg]){
use[numedg]=false;
Edge q = E[numedg];
ind[q.v]--;
if(ind[q.v]==){
Q.push(q.v); ind[q.v]=k+;
}
cL = cR = q.v;
cans =ind[q.v];
T.update(,,n);
}
}
}
int ans[maxn];
int main()
{
int n,m,k; while(scanf("%d%d%d",&n,&m,&k)==){
init(n);
for(int i=; i<m; i++){
int u,v;
scanf("%d%d",&u,&v);
add_edg(u,v);
ind[v]++;
}
while(!Q.empty())Q.pop();
for(int i =; i<=n; i++){
if(ind[i]==){
Q.push(i);
ind[i]=k+;
}
}
T.build(,,n);
int st=;
while(!Q.empty()){
int top = Q.top();
int nk = jud(k,n);
if(nk>top){
k-=ind[nk];
solve1(nk,k,n);
Q.push(nk);
}else{
Q.pop();
ans[st++]=top;
solve2(top,k,n);
}
}
for(int i=; i<n-; i++) printf("%d ",ans[i]);
printf("%d\n",ans[n-]);
} return ;
}
上一篇:Android网络框架Volley(体验篇)


下一篇:【原创】大叔经验分享(20)spark job之间会停顿几分钟