zoukankan      html  css  js  c++  java
  • 题解[P4350Export Estimate]

    原题链接

    题意:
    给定一张无向连通图,每次询问时保留边权 (geq t) 的边,并对这张图进行如下操作:

    • 从小到大枚举每个点 (i) ,若其度数为 (0) 直接删去。
    • 若其度数为 (2) ,则找出连向 (i) 的点 (u,v)(可能相同),并删去点 (i) 以及连向 (u,v) 的两条边,再添加 (u,v) 一条边。((u,v) 相同时形成一个自环)

    ( ext{Sulotion})

    如果将询问按 (t) 从大到小排序,那每次需要的图就由之前的加上一些边得到,边权递减。

    先考虑每个操作流程对点与边的影响。

    设一个度数为 (k) 的点称为 (k) 度点。则可以发现在第一、第二个流程中受影响的点仅有 (0) 度点与 (2) 度点。

    每个 (0) 度点会将点的总量减 (1) ,而每个 (2) 度点会将点总数减 (1) ,且将边总数减 (1) 。而每个对 (2) 度点的操作不会影响其他点的度数。

    所以只需统计出 (0) 度点与 (2) 度点的个数 (sum_0,sum_2) ,以及出现过得边的个数 (edg) 。那总点数就是 (n-sum_0-sum_2), 总边数就是 (edge-sum_2) 。由于是动态加边,可以用并查集维护连通块内 (2) 度点与 (0) 度点个数。

    但事实上并非如此,在某个连同图是一个单纯的环时会出现问题。

    因为按照上文说法这个环会没有点剩余,而环上所有点都为 (2) 度点。但它最终剩余的是一个自环,点数与变数要加上 (1) 。设纯环个数为 (k),则最终点与边数为 (n-sum_0,-sum_2+k)(edge-sum_2+k)

    而由于纯环上所有点都为二度点,并查集同时维护点的个数后是容易判定的。

    时间复杂度 (O(nalpha(n)))

    代码:(个人认为实现方法还算简单)

    #include<bits/stdc++.h>
    using namespace std;
    const int N=3e5+10;
    int n,m,s,x,y,v,ax,ay;
    int s_nd2,s_nd0,s_cyc;
    struct node{
    	int x,y,w;
    	bool operator <(const node &x)const{return w>x.w;}
    }e[N],q[N],ans[N];
    int f[N],sz[N],sz2[N],deg[N];bool cyc[N];char ch;
    inline int getf(int x){while(x^f[x])x=f[x]=f[f[x]];return x;}
    inline void read(int &x){
    	x=0;ch=getchar();while(ch<48)ch=getchar();
    	while(ch>47)x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    }
    void write(int x){if(x>9)write(x/10);putchar(48+x%10);}
    main(){
    	read(n),read(m);register int i,j=0,s,t;
    	for(i=1;i<=m;++i)read(x),read(y),read(v),e[i]=(node){x,y,v};
    	read(s);for(i=1;i<=s;++i)read(v),q[i]=(node){i,0,v};
    	sort(e+1,e+m+1);sort(q+1,q+s+1);
    	s_nd0=n;
    	for(i=1;i<=n;++i)sz[i]=1,f[i]=i;
    	for(i=1;i<=s;++i){
    		while(e[j+1].w>=q[i].w&&j<m){
    			++j;
    			x=e[j].x,y=e[j].y;ax=getf(x),ay=getf(y);
    			if(!deg[x])--s_nd0;if(deg[x]==2)--s_nd2,--sz2[ax];
    			if(!deg[y])--s_nd0;if(deg[y]==2)--s_nd2,--sz2[ay];
    			++deg[x];++deg[y];
    			s_cyc-=cyc[ax];cyc[ax]=0;
    			if(ax^ay)f[ay]=ax,s_cyc-=cyc[ay],sz[ax]+=sz[ay],sz2[ax]+=sz2[ay];
    			if(deg[x]==2)++s_nd2,++sz2[ax];
    			if(deg[y]==2)++s_nd2,++sz2[ax];
    			if(sz2[ax]==sz[ax])cyc[ax]=1,++s_cyc;
    		}
    		ans[q[i].x]=(node){n-s_nd0-s_nd2+s_cyc,j-s_nd2+s_cyc};
    	}
    	for(i=1;i<=s;++i)write(ans[i].x),putchar(' '),write(ans[i].y),putchar('
    ');
    }
    
  • 相关阅读:
    ruby基础语法
    几种移动开发技术的比较和选型
    iOS中UIWebView与其中网页的javascript的交互
    android混合开发,webview的java与js互操作
    在学Go语言
    从11对战平台获取玩家数据进行分析
    本地json文件的编辑器,node-webkit开发的exe程序
    51单片机实现多模式计算器
    如何得到个性化banner
    php文件下载服务器代码
  • 原文地址:https://www.cnblogs.com/Y-B-X/p/15440977.html
Copyright © 2011-2022 走看看