CF 603 E题解

89 篇文章 1 订阅

CF 603 E题解

又是我做不出来的题

这题我分析到了“对于每一个询问,查询最小的bound,使得将 w ≤ b o u n d w\leq bound wbound的边都加入,使得所有联通快都是偶数”这一步,然后就卡住了。

可以发现,所有询问的答案不增的,若设无解为 ∞ \infty

然而还是不会做。

不过我们回忆一下“决策单调性”来优化dp过程的做法。

定义 w o r k ( l , r , L , R ) work(l,r,L,R) work(l,r,L,R)表示已知 ⋂ i = l r a n s w e r i ∈ [ L , R ] \bigcap_{i=l}^r answer_{i}\in [L,R] i=lransweri[L,R]。然后计算出所有 l l l r r r之间的 a n s w e r answer answer

m i d = ⌊ l + r 2 ⌋ mid=\lfloor\frac{l+r}{2} \rfloor mid=2l+r,则我们只需要计算出 a n s w e r m i d answer_{mid} answermid,就可以递归算出: w o r k ( l , m i d − 1 , L , a n s w e r m i d ) , w o r k ( m i d + 1 , r , a n s w e r m i d , R ) work(l,mid-1,L,answer_{mid}),work(mid+1,r,answer_{mid},R) work(l,mid1,L,answermid),work(mid+1,r,answermid,R)了。

如何计算 a n s w e r m i d answer_{mid} answermid呢?

可以用并查集!

假设我们已经加入了 w < L w<L w<L的所有边,然后我们依次加入 L L L R R 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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值