• 题解[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('
    ');
    }
    
  • 相关阅读:
    (转)分布式加载网站的静态文件
    (转)一步一步Asp.Net MVC系列_权限管理设计起始篇
    (转)SQL Server复制入门(一)复制简介
    (转)【配置属性】—Entity Framework实例详解
    (转)动态Entity Framework查询:Dynamic Query 介绍
    (转)用扩展方法优化多条件查询
    (转)一步一步Asp.Net MVC系列_权限管理之权限控制
    (转 )Entity Framework Code First使用者的福音 EF Power Tool使用记之二(问题探究)
    (转)【工欲善其事必先利其器】—Entity Framework实例详解
    (转)C#/winform 腾讯QQ注册
  • 原文地址:https://www.cnblogs.com/Y-B-X/p/15440977.html
Copyright © 2020-2023  润新知