zoukankan      html  css  js  c++  java
  • 题解 CF1037E 【Trips】

    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
    ",d[i].ans);  //正向输出答案
    	return 0;
    }
    
  • 相关阅读:
    kali64位 安装 adb
    ZendStudio在kali下无法启动
    VS2010配置OpenGL开发环境(转)
    OpenGL程序无法启动此应用程序,因为计算机中丢失glut32.dll(转))
    vs2010 出错:error LNK1123: 转换到 COFF 期间失败: 文件无效或损坏(转)
    AnyCAD三维控件(转)
    C# WinForm程序中使用Unity3D控件 (转)
    SharpGL学习笔记(一) 平台构建与Opengl的hello World (转)
    c# Invoke的新用法
    c# 在静态方法里,怎么能得到调用者的类名?
  • 原文地址:https://www.cnblogs.com/ALANALLEN21LOVE28/p/11313020.html
Copyright © 2011-2022 走看看