CF 603 E题解
CF 603 E题解
又是我做不出来的题。
这题我分析到了“对于每一个询问,查询最小的bound,使得将\(w\leq bound\)的边都加入,使得所有联通快都是偶数”这一步,然后就卡住了。
可以发现,所有询问的答案不增的,若设无解为\(\infty\)。
然而还是不会做。
不过我们回忆一下“决策单调性”来优化dp过程的做法。
定义\(work(l,r,L,R)\)表示已知\(\bigcap_{i=l}^r answer_{i}\in [L,R]\)。然后计算出所有\(l\)到\(r\)之间的\(answer\)。
设\(mid=\lfloor\frac{l+r}{2} \rfloor\),则我们只需要计算出\(answer_{mid}\),就可以递归算出:\(work(l,mid-1,L,answer_{mid}),work(mid+1,r,answer_{mid},R)\)了。
如何计算\(answer_{mid}\)呢?
可以用并查集!
假设我们已经加入了\(w<L\)的所有边,然后我们依次加入\(L\)到\(R\)的边,然后判定有没有大小为奇数的联通快就行了。
这个并查集还需要支持撤销!
另一个相似的题目:arc 045 d みんな仲良し高橋君
/*
{
######################
# Author #
# Gary #
# 2021 #
######################
*/
#include<bits/stdc++.h>
#define rb(a,b,c) for(int a=b;a<=c;++a)
#define rl(a,b,c) for(int a=b;a>=c;--a)
#define LL long long
#define IT iterator
#define PB push_back
#define II(a,b) make_pair(a,b)
#define FIR first
#define SEC second
#define FREO freopen("check.out","w",stdout)
#define rep(a,b) for(int a=0;a<b;++a)
#define SRAND mt19937 rng(chrono::steady_clock::now().time_since_epoch().count())
#define random(a) rng()%a
#define ALL(a) a.begin(),a.end()
#define POB pop_back
#define ff fflush(stdout)
#define fastio ios::sync_with_stdio(false)
#define check_min(a,b) a=min(a,b)
#define check_max(a,b) a=max(a,b)
using namespace std;
//inline int read(){
// int x=0;
// char ch=getchar();
// while(ch<'0'||ch>'9'){
// ch=getchar();
// }
// while(ch>='0'&&ch<='9'){
// x=(x<<1)+(x<<3)+(ch^48);
// ch=getchar();
// }
// return x;
//}
const int INF=0x3f3f3f3f;
typedef pair<int,int> mp;
/*}
*/
const int MAXN=1e5+20;
pair<mp,int> e[MAXN*3];
struct operation{
int index,farnk;
operation(){}
operation(int a,int b){
index=a;farnk=b;
}
};
struct DSU{
vector<operation> vec;
int fa[MAXN],siz[MAXN],rnk[MAXN],cnt;
DSU(){}
DSU(int n){
cnt=n;
rb(i,1,n) fa[i]=i,siz[i]=1,rnk[i]=1;
}
int root(int v){
return (fa[v]==v? v:root(fa[v]));
}
void merge(int u,int v){
u=root(u);
v=root(v);
if(u==v){
vec.PB(operation(0,0));
return;
}
if(rnk[u]>rnk[v]) swap(u,v);
fa[u]=v;
cnt-=siz[u]%2;
cnt-=siz[v]%2;
vec.PB(operation(u,rnk[v]));
siz[v]+=siz[u];
if(rnk[u]==rnk[v]) rnk[v]++;
cnt+=siz[v]%2;
}
void undo(){
operation now=vec.back();
vec.POB();
if(now.farnk==0) return ;
int u,farnk,v;
u=now.index,farnk=now.farnk;
v=fa[u];
fa[u]=u;
cnt-=siz[v]%2;
siz[v]-=siz[u];
rnk[v]=farnk;
cnt+=siz[v]%2;
cnt+=siz[u]%2;
}
}dsu;
int n,m,rest[300000+20];
int order[300000+20];
bool cmp(int A,int B){
return e[A].SEC<e[B].SEC;
}
void solve(int l,int r,int L,int R){
if(l>r) return ;
int mid=(l+r)>>1;
int cnt1=0;
rb(i,l,mid){
if(e[i].SEC<=e[order[L]].SEC){
++cnt1;
dsu.merge(e[i].FIR.FIR,e[i].FIR.SEC);
}
}
int now=L;
int cnt2=0;
while(dsu.cnt){
now++;
if(now>R) break;
if(order[now]<=mid){
cnt2++;
dsu.merge(e[order[now]].FIR.FIR,e[order[now]].FIR.SEC);
}
}
while(now<R&&e[order[now+1]].SEC==e[order[now]].SEC){
++now;
if(order[now]<=mid){
cnt2++;
dsu.merge(e[order[now]].FIR.FIR,e[order[now]].FIR.SEC);
}
}
rb(i,1,cnt1+cnt2) dsu.undo();
if(now>R){
rb(i,l,mid){
rest[i]=-1;
}
now=R;
}
else{
rest[mid]=now;
cnt1=0;
rb(i,L,now){
if(order[i]<l){
cnt1++;
dsu.merge(e[order[i]].FIR.FIR,e[order[i]].FIR.SEC);
}
}
solve(l,mid-1,now,R);
rb(i,1,cnt1) dsu.undo();
}
cnt1=0;
rb(i,l,mid){
if(e[i].SEC<=e[order[L]].SEC){
++cnt1;
dsu.merge(e[i].FIR.FIR,e[i].FIR.SEC);
}
}
solve(mid+1,r,L,now);
rb(i,1,cnt1) dsu.undo();
}
int main(){
scanf("%d%d",&n,&m);
dsu=DSU(n);
rb(i,1,m){
int u,v,c;
scanf("%d%d%d",&u,&v,&c);
e[i]=II(II(u,v),c);
}
rb(i,1,m) order[i]=i;
sort(order+1,order+1+m,cmp);
solve(1,m,1,m);
rb(i,1,m){
printf("%d\n",rest[i]>=1? e[order[rest[i]]].SEC:-1);
}
return 0;
}