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
",ans);
69     return 0;
70 }
原文地址:https://www.cnblogs.com/Ressed/p/9911824.html