luogu5008 逛庭院 (tarjan缩点)
首先如果这是一个DAG,我按照拓扑序倒着去选,一定能选到所有入度不为0的点
然后考虑有环的情况 我们拎出来一个强连通分量 先假设它缩点以后是没有入度的
那我最后它里面一定至少剩一个不能选 因为就剩一个的时候肯定没有入度呀
那我显然可以把它看成是一个只有一个点入度为0的DAG 而且那个入度为0的点可以任选 那就是刚才的结论了
如果它缩点以后有入度 那它就整个都能选了
所以就缩点以后把每个入度为0的点内权值最小的那个去掉 最后取前k大的就行了
这里有一个trick:可以用nth_element找到第k大 然后扫一遍把所有大于它的都加上,是O(n)的
然而并不需要2333
1 #include<bits/stdc++.h> 2 #define CLR(a,x) memset(a,x,sizeof(a)) 3 using namespace std; 4 typedef long long ll; 5 typedef pair<int,int> pa; 6 const int maxn=5e5+10,maxm=2e6+10; 7 8 inline ll rd(){ 9 ll x=0;char c=getchar();int neg=1; 10 while(c<'0'||c>'9'){if(c=='-') neg=-1;c=getchar();} 11 while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar(); 12 return x*neg; 13 } 14 15 int eg[maxm][2],egh[maxn],ect; 16 int N,M,K,dfn[maxn],tot,low[maxn],stk[maxn],sh,bel[maxn],pct; 17 int lst[maxn],v[maxn]; 18 bool instk[maxn],ine[maxn]; 19 20 inline void adeg(int a,int b){ 21 eg[++ect][0]=b,eg[ect][1]=egh[a],egh[a]=ect; 22 } 23 24 void tarjan(int x){ 25 dfn[x]=low[x]=++tot; 26 instk[x]=1,stk[++sh]=x; 27 for(int i=egh[x];i;i=eg[i][1]){ 28 int b=eg[i][0]; 29 if(!dfn[b]) tarjan(b),low[x]=min(low[x],low[b]); 30 else if(instk[b]) low[x]=min(low[x],dfn[b]); 31 } 32 if(low[x]==dfn[x]){ 33 ++pct; 34 int mi=23333; 35 while(1){ 36 bel[stk[sh]]=pct; 37 instk[stk[sh]]=0; 38 if(v[stk[sh]]<mi) mi=v[stk[sh]],lst[pct]=stk[sh]; 39 if(stk[sh--]==x) break; 40 } 41 } 42 } 43 44 int main(){ 45 //freopen("","r",stdin); 46 int i,j,k; 47 N=rd(),M=rd(),K=rd(); 48 for(i=1;i<=N;i++) v[i]=rd(); 49 for(i=1;i<=M;i++){ 50 int a=rd(),b=rd(); 51 adeg(a,b); 52 } 53 for(i=1;i<=N;i++) 54 if(!dfn[i]) tarjan(i); 55 for(i=1;i<=N;i++){ 56 for(j=egh[i];j;j=eg[j][1]){ 57 if(bel[eg[j][0]]!=bel[i]) 58 ine[bel[eg[j][0]]]=1; 59 } 60 } 61 for(i=1;i<=pct;i++){ 62 if(!ine[i]) v[lst[i]]=0; 63 } 64 sort(v+1,v+N+1); 65 int ans=0; 66 for(i=N;i>=N-K+1;i--) 67 ans+=v[i]; 68 printf("%d\n",ans); 69 return 0; 70 }