[noi110]翘课

发现加边操作不好处理,因此考虑先加完所有边后删边。

删去一对边xy,如果两者中有一个不翘课显然没有意义,那么如果都翘课了那么就对他们进行判断,如果无法翘课就继续搜下去。

这样的时间复杂度看上去似乎是o(nm)的,但注意到每一个点最多由翘课变为不翘课一次,因此是o(n+m)的。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 queue<int>q;
 4 struct ji{
 5     int nex,to;
 6 }edge[400001];
 7 int E,n,m,k,head[200001],x[200001],y[200001],d[200001],ans[200001];
 8 bool vis[200001],flag[400001];
 9 void add(int x,int y){
10     edge[E].nex=head[x];
11     edge[E].to=y;
12     head[x]=E++;
13 }
14 void pus(int t){
15     if (d[t]<k){
16         q.push(t);
17         ans[0]-=(vis[t]=1);
18     } 
19 }
20 void erase(){
21     while (!q.empty()){
22         int k=q.front();
23         q.pop();
24         for(int i=head[k];i!=-1;i=edge[i].nex)
25             if ((!vis[edge[i].to])&&(!flag[i])){
26                 flag[i]=flag[i^1]=1;
27                 d[edge[i].to]--;
28                 pus(edge[i].to);
29             } 
30     }
31 }
32 int main(){
33     memset(head,-1,sizeof(head));
34     scanf("%d%d%d",&n,&m,&k);
35     for(int i=1;i<=m;i++){
36         scanf("%d%d",&x[i],&y[i]);
37         add(x[i],y[i]);
38         add(y[i],x[i]);
39         d[x[i]]++;
40         d[y[i]]++;
41     }
42     ans[0]=n;
43     for(int i=1;i<=n;i++)pus(i);
44     for(int i=m;i;i--){
45         erase();
46         ans[i]=ans[0];
47         if (vis[x[i]]+vis[y[i]]==0){
48             d[x[i]]--;
49             d[y[i]]--;
50         }
51         flag[i*2-1]=flag[i*2-2]=1;
52         if (!vis[x[i]])pus(x[i]);
53         if (!vis[y[i]])pus(y[i]);
54     }
55     for(int i=1;i<=m;i++)printf("%d\n",ans[i]);
56 } 
View Code
原文地址:https://www.cnblogs.com/PYWBKTDA/p/11272291.html