zoukankan      html  css  js  c++  java
  • 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 }
  • 相关阅读:
    每天一个linux命令(6):mv命令
    每天一个linux命令(5):rm 命令
    每天一个linux命令(4):mkdir命令
    每天一个linux命令(3):pwd命令
    每天一个linux命令(2):cd命令
    每天一个linux命令(1):ls命令
    Linux下svn命令详解
    Linux下SVN安装配置
    SVN命令使用详解
    分布式Web服务器架构
  • 原文地址:https://www.cnblogs.com/guapisolo/p/9839144.html
Copyright © 2011-2022 走看看