[noi110]翘课
发现加边操作不好处理,因此考虑先加完所有边后删边。
删去一对边x到y,如果两者中有一个不翘课显然没有意义,那么如果都翘课了那么就对他们进行判断,如果无法翘课就继续搜下去。
这样的时间复杂度看上去似乎是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 }