【BZOJ4452】[Cerc2015]Export Estimate 并查集
【BZOJ4452】[Cerc2015]Export Estimate
Description
给你一个n个点m条边的无向图,每条边有权值,我们可以选择一个整数lim来生成一个新的图,过程如下:
1.先将原图中边权小于lim的边删掉
2.依次从1到n枚举每个点
(a)如果这个点没有边于它相连,这个点将会被删去
(b)如果这个点只与两条不相同的边x,y相连,设这两条边的另一个点分别为a,b,如果a,b和这个点都不相同(a,b可以相同),则依次做如下操作:
(i)删去边x,y
(ii)删去这个点
(iii)在a,b之间建立一条新的边
下面这个例子lim=95:
数据保证原图没有重边和自环,但不保证经过如上操作后的图没有重边和自环。
现在我们想知道当lim取若干值时,由原图生成的新图的点数和边数是多少。
Input
第一行两个数n,m,表示原图有n点m条边。
接下来m行,每行三个数a,b,c,表示a和b之间有一条边权为c的双向边。
接下来一行一个数q,表示有q次询问。
接下来一行q个数,k1,k2,...,kq。
Output
总共q行,每行两个数,表示lim取ki时,生成的新图的点数和边数
Sample Input
Sample Input1:
6 7
1 2 20
2 3 80
2 5 100
3 5 50
3 4 100
5 6 90
4 6 100
4
25 75 85 95
Sample Input2:
10 14
2 7 150
1 2 100
2 3 150
3 1 200
1 4 60
4 5 20
2 5 100
5 6 90
6 7 120
7 5 130
6 8 50
8 9 200
9 10 200
10 7 200
5
300 50 95 100 110
6 7
1 2 20
2 3 80
2 5 100
3 5 50
3 4 100
5 6 90
4 6 100
4
25 75 85 95
Sample Input2:
10 14
2 7 150
1 2 100
2 3 150
3 1 200
1 4 60
4 5 20
2 5 100
5 6 90
6 7 120
7 5 130
6 8 50
8 9 200
9 10 200
10 7 200
5
300 50 95 100 110
Sample Output
Sample Output1:
2 3
1 1
2 1
4 2
Sample Output2:
0 0
6 9
4 5
4 5
5 4
数据范围:
1<=n<=300000
1<=m<=300000
0<=c<=300000
1<=q<=300000
0<=ki<=300000
2 3
1 1
2 1
4 2
Sample Output2:
0 0
6 9
4 5
4 5
5 4
数据范围:
1<=n<=300000
1<=m<=300000
0<=c<=300000
1<=q<=300000
0<=ki<=300000
题解:发现在删除一个点的时候,其余点的度数不变,除了形成自环的情况,再结合几个例子就能发现:
最后的点数=n-度数为0的点的个数-度数为2的点的个数+环数
最后的边数=m-度数为2的点的个数+环数
所以用并查集来维护有几个环即可,具体地,维护一个连通块中点的个数以及度数为2的点的个数,如果相等则说明这是一个环。
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; const int maxn=300010; int n,m,Q; int s0,s2,cir; struct node { int a,b,c; }p[maxn]; struct query { int org,k; }q[maxn]; int f[maxn],siz[maxn],sz[maxn],d[maxn],a1[maxn],a2[maxn]; bool cmpc(const node &a,const node &b) { return a.c>b.c; } bool cmpk(const query &a,const query &b) { return a.k>b.k; } int find(int x) { return (f[x]==x)?x:(f[x]=find(f[x])); } inline int rd() { int ret=0,f=1; char gc=getchar(); while(gc<'0'||gc>'9') {if(gc=='-') f=-f; gc=getchar();} while(gc>='0'&&gc<='9') ret=ret*10+(gc^'0'),gc=getchar(); return ret*f; } int main() { n=rd(),m=rd(); int i,j,a,b; for(i=1;i<=m;i++) p[i].a=rd(),p[i].b=rd(),p[i].c=rd(); sort(p+1,p+m+1,cmpc); Q=rd(); for(i=1;i<=Q;i++) q[i].org=i,q[i].k=rd(); sort(q+1,q+Q+1,cmpk); for(i=1;i<=n;i++) siz[i]=1,f[i]=i; s0=n; for(i=j=1;i<=m;i++) { for(;j<=Q&&q[j].k>p[i].c;j++) a1[q[j].org]=n-s0-s2+cir,a2[q[j].org]=i-1-s2+cir; s0-=(!d[p[i].a])+(!d[p[i].b]),s2-=(d[p[i].a]==2)+(d[p[i].b]==2); a=find(p[i].a),b=find(p[i].b); cir-=(siz[a]==sz[a])+(a!=b&&siz[b]==sz[b]); sz[a]-=(d[p[i].a]==2),sz[b]-=(d[p[i].b]==2); d[p[i].a]++,d[p[i].b]++; s2+=(d[p[i].a]==2)+(d[p[i].b]==2); sz[a]+=(d[p[i].a]==2),sz[b]+=(d[p[i].b]==2); if(find(a)!=find(b)) siz[b]+=siz[a],sz[b]+=sz[a],f[a]=b; cir+=(siz[b]==sz[b]); } for(;j<=Q;j++) a1[q[j].org]=n-s0-s2+cir,a2[q[j].org]=m-s2+cir; for(i=1;i<=Q;i++) printf("%d %d\n",a1[i],a2[i]); return 0; }
| 欢迎来原网站坐坐! >原文链接<