CF1037E Trips (离线+图上构造)

题目大意:一共有n个人,每天早上会有两个人成为朋友,朋友关系不具有传递性,晚上,它们会组织旅游,如果一个人去旅游,那么他不少于$k$个朋友也要和他去旅游,求每天的最大旅游人数

一开始并没有想到反向建图,并查集搞了好久也没出解,看了题解的思路,大概是这样的

转化问题,反向建图,把正序往图里建边换成每次倒序在图里删边。

显然,一开始/删掉边之后,度小于K的点一定不可用,那么把它删掉,和它相连的边也删掉

那么可能这个点删掉以后,和它相连的某个点度也小于K了,再把那个点也删掉...发现这是一个类似于拓扑的过程

由于每个点只会被删掉1次,所以复杂度大约是$O(n+m)$

边全都加完的图中,也可能有些点既没有入度也没有出度,答案里要把它们去掉

 1 #include <set>
 2 #include <queue>
 3 #include <cstdio>
 4 #include <cstring>
 5 #include <algorithm>
 6 #define N 200100
 7 #define ll long long
 8 using namespace std;
 9 //re
10 int gint()
11 {
12     int ret=0,fh=1;char c=getchar();
13     while(c<'0'||c>'9'){if(c=='-')fh=-1;c=getchar();}
14     while(c>='0'&c<='9'){ret=ret*10+c-'0';c=getchar();}
15     return ret*fh;
16 }
17 int n,m,K,ma,cte,sum;
18 int head[N],inc[N],ans[N];
19 struct Edge{int to,nxt,val;}edge[N*2];
20 void ae(int u,int v){
21     cte++;edge[cte].to=v,inc[v]++;
22     edge[cte].nxt=head[u],head[u]=cte;}
23 queue<int>que;
24 void Pop(int x)
25 {
26     que.push(x);
27     while(!que.empty())
28     {
29         int x=que.front();que.pop();
30         if(head[x]!=0) sum--;
31         for(int j=head[x];j;j=edge[j].nxt){
32             if(edge[j].val==-1)continue;
33             edge[j].val=edge[j^1].val=-1;
34             int v=edge[j].to;
35             inc[v]--;
36             if(inc[v]<K) que.push(v);
37         }head[x]=0;
38     } 
39 }
40 
41 int main()
42 {
43     scanf("%d%d%d",&n,&m,&K);
44     int x,y,z;cte=1;sum=n;
45     for(int i=1;i<=m;i++)
46         x=gint(),y=gint(),ae(x,y),ae(y,x);
47     for(int i=1;i<=n;i++)
48         if(head[i]==0) sum--;
49     for(int i=1;i<=n;i++)
50         if(inc[i]<K) Pop(i);
51     for(int j=m;j>=1;j--)
52     {
53         ans[j]=sum;
54         if(edge[j<<1].val==-1) 
55         {continue;}
56         x=edge[j<<1].to;
57         y=edge[j<<1|1].to;
58         inc[x]--,inc[y]--;
59         edge[j<<1].val=edge[j<<1|1].val=-1;
60         if(inc[x]<K) Pop(x);
61         if(inc[y]<K) Pop(y);
62     }
63     for(int j=1;j<=m;j++)
64         printf("%d
",ans[j]);
65     return 0;
66 }
原文地址:https://www.cnblogs.com/guapisolo/p/9839144.html