zoukankan      html  css  js  c++  java
  • CF 603 E题解

    CF 603 E题解

    又是我做不出来的题

    这题我分析到了“对于每一个询问,查询最小的bound,使得将(wleq bound)的边都加入,使得所有联通快都是偶数”这一步,然后就卡住了。

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

    然而还是不会做。

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

    定义(work(l,r,L,R))表示已知(igcap_{i=l}^r answer_{i}in [L,R])。然后计算出所有(l)(r)之间的(answer)

    (mid=lfloorfrac{l+r}{2} floor),则我们只需要计算出(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
    ",rest[i]>=1? e[order[rest[i]]].SEC:-1);
    	}
    	return 0;
    }
    
  • 相关阅读:
    C#(winform)浏览按钮
    C#操作CSV存取类
    忘记windows的登陆密码
    exe文件打开方式(恢复EXE文件关联)
    MongoDB 搭建副本集
    Performance Monitor3:监控SQL Server的内存压力
    大数据操作:删除和去重
    SSRS配置2:加密管理
    SSISDB7:当前正在运行的Package及其Executable
    不再迷惑,无值和NULL值
  • 原文地址:https://www.cnblogs.com/gary-2005/p/14244058.html
Copyright © 2011-2022 走看看