码迷,mamicode.com
首页 > 其他好文 > 详细

题解 CF1037E 【Trips】

时间:2019-08-07 09:25:52      阅读:81      评论:0      收藏:0      [点我收藏+]

标签:char   fir   name   --   use   ble   联通   clu   mod   

first

题目大意:给一幅图,边从 0 开始每天多一条边,问每天增加边之后能够有多少人去旅游。能去旅游的定义是只有当联通的点的度数都大于等于 k 才能去旅游,否则都不能去旅游。询问每天最多能去旅游的点的数量

second

很明显正向不太好做,于是离线建边的信息,考虑反向跑:每次都删去度小于\(k\)的点(对点标记),删去与其相连的边(同样对边进行标号标记即可),将与其相连的还未删去的点的度修改一下,反向统计答案即可。

third

代码里有详注
(这里使用小根配对堆维护度的取出):

#include<iostream>
#include<cstdio>
#include<vector>
#include<cstring>
#include<ext/pb_ds/priority_queue.hpp>
using namespace std;
#define in read()
#define fur(i,a,b) for(int i=a;i<=b;++i)
#define fdr(i,a,b) for(int i=a;i>=b;--i)
#define pa pair<int,int>
#define heep __gnu_pbds::priority_queue<pa,greater<pa> >
#define nm make_pair
inline int read()  //读入优化
{
    int x=0,f=1;char ch=getchar();
    for(;!isalnum(ch);ch=getchar()) if(ch=='-') f=-1;
    for(;isalnum(ch);ch=getchar()) x=x*10+ch-'0';
    return x*f;
}
const int xx=2e5+10;
int du[xx],cnt;   //点的度与当前剩余的未被删的点的数量
vector<pa>e[xx];  //存储两个信息:连的点与边的编号
struct edge{int u,v,ans;bool use;}d[xx];  //存储边的两端,该时间的答案与该边是否被删
heep p; //小根配对堆存度与点编号
heep::point_iterator id[xx];
bool cut[xx];  //点是否被删
int main()
{
    int n=in,m=in,k=in;
    fur(i,1,m)
    {
        int x=in,y=in;
        d[i].u=x,d[i].v=y;
        e[x].push_back(nm(y,i));
        e[y].push_back(nm(x,i));
        ++du[x];++du[y];
    }
    fur(i,1,n) id[i]=p.push(nm(du[i],i)); //将度压入堆
    cnt=n;  //初始化为被删的点的数量
    fdr(i,m,1)
    {
        while(!p.empty()&&p.top().first<k)
        {
            int u=p.top().second;p.pop();
            cut[u]=true;du[u]=0;  //删
            --cnt;                         //点
            fur(j,0,(int)e[u].size()-1)
            {
                if(cut[e[u][j].first]) continue;  //连点已被删,跳过
                if(d[e[u][j].second].use) continue; //连边已被删,跳过
                d[e[u][j].second].use=true; //否则删边
                --du[e[u][j].first];  //修改连点的度
                p.modify(id[e[u][j].first],nm(du[e[u][j].first],e[u][j].first)); //修改ing
            }
        }
        d[i].ans=cnt; //存储答案
        if(!d[i].use)  //若该边没被删
        {
            if(cut[d[i].u]||cut[d[i].v]) continue; //若边的两端任何一点被删,跳过
            --du[d[i].u];                     //否则修改点的度
            --du[d[i].v];
            p.modify(id[d[i].u],nm(du[d[i].u],d[i].u));
            p.modify(id[d[i].v],nm(du[d[i].v],d[i].v));
            d[i].use=true;   //且删边
        }
    }
    fur(i,1,m) printf("%d\n",d[i].ans);  //正向输出答案
    return 0;
}

题解 CF1037E 【Trips】

标签:char   fir   name   --   use   ble   联通   clu   mod   

原文地址:https://www.cnblogs.com/ALANALLEN21LOVE28/p/11313020.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!