[cf603E]Pastoral Oddities

一张图合法当且仅当每一个连通块大小都为偶数

必要性:对于一个奇数个的连通块,若每一个点度数都为奇数,那么度数和也为奇数,而每一条边带来的度都为2,因此度数和应该为偶数,矛盾

充分性:一个偶数个点的连通块,必然存在一棵生成树,按照以下方式从底往上,通过每一个点到其父亲的边来控制度数为奇数,由于总度数和为偶数,因此根的度数必然为奇数,即符合条件

对于一个询问,可以直接二分答案并插入小于等于其的边,通过并查集维护连通块奇偶性来判断是否合法

对于多个询问,考虑整体二分,对于当前答案区间$[x,y]$,由于答案是单调递减的(-1视为$infty$),因此所对应的必然为连续区间$[l,r]$(在这之前我们已经插入了$[1,l]$中边权在$[1,x]$中的边)

对于答案mid,再将其划分为两部分,答案大于mid当且仅当插入在其之前且边权在$[1,mid]$中的边不合法,首先要插入$l$之前边权在$(x,mid]$的边,再枚举断点的位置并插入$[1,mid]$中的边直至合法

分两类讨论,若初始合法,那么区间$[l,r]$的答案都为$x$,否则断点必然为第一个答案小于等于mid的位置,从其划分即可

(特别的,初始若第1条边边权最小,需要将第1条边加入)

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define N 300005
 4 struct ji{
 5     int x,y,z;
 6 }e[N],ee[N];
 7 int n,m,tot,st[N],f[N],sz[N],ans[N];
 8 bool cmp(ji x,ji y){
 9     return e[x.z].z<e[y.z].z;
10 }
11 int find(int k){
12     if (k==f[k])return k;
13     return find(f[k]);
14 }
15 void merge(int x,int y){
16     x=find(x),y=find(y);
17     if (x!=y){
18         if (sz[x]<sz[y])swap(x,y);
19         tot-=(sz[x]&1)+(sz[y]&1)-((sz[x]+sz[y])&1);
20         f[y]=x;
21         sz[x]+=sz[y];
22         st[++st[0]]=y;
23     }
24 }
25 void clear(){
26     int y=st[st[0]--],x=f[y];
27     f[y]=y;
28     sz[x]-=sz[y];
29     tot+=(sz[x]&1)+(sz[y]&1)-((sz[x]+sz[y])&1);
30 }
31 void dfs(int l,int r,int x,int y){
32     if (l>r)return;
33     if (x==y){
34         for(int i=l;i<=r;i++)
35             if (x==m)ans[i]=-1;
36             else ans[i]=e[ee[x].z].z;
37         return;
38     } 
39     int s=(x+y>>1),now=st[0],mid;
40     for(int i=x+1;i<=s;i++)
41         if (ee[i].z<=l)merge(ee[i].x,ee[i].y);
42     if (!tot)mid=l;
43     else
44         for(mid=l+1;(tot)&&(mid<=r);mid++)
45             if (e[mid].z<=e[ee[s].z].z){
46                 merge(e[mid].x,e[mid].y);
47                 if (!tot)break;
48             }
49     while (st[0]>now)clear();
50     for(int i=x+1;i<=s+1;i++)
51         if (ee[i].z<=l)merge(ee[i].x,ee[i].y);
52     dfs(l,mid-1,s+1,y);
53     while (st[0]>now)clear();
54     for(int i=l+1;i<=mid;i++)
55         if (e[i].z<=e[ee[x].z].z)merge(e[i].x,e[i].y);
56     dfs(mid,r,x,s);
57     while (st[0]>now)clear();
58 }
59 int main(){
60     scanf("%d%d",&n,&m);
61     for(int i=1;i<=m;i++){
62         scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].z);
63         ee[i]=e[i];
64         ee[i].z=i;
65     }
66     e[++m]=ji{1,1,0x3f3f3f3f};
67     ee[m]=ji{1,1,m};
68     sort(ee+1,ee+m+1,cmp);
69     tot=n;
70     for(int i=1;i<=n;i++){
71         f[i]=i;
72         sz[i]=1;
73     }
74     if (ee[1].z==1)merge(e[1].x,e[1].y);
75     dfs(1,m-1,1,m);
76     for(int i=1;i<m;i++)printf("%d
",ans[i]);
77 }
View Code
原文地址:https://www.cnblogs.com/PYWBKTDA/p/13910275.html