• 【CF603E】Pastoral Oddities cdq分治+并查集


    【CF603E】Pastoral Oddities

    题意:有n个点,依次加入m条边权为$l_i$的无向边,每次加入后询问:当前图是否存在一个生成子图,满足所有点的度数都是奇数。如果有,输出这个生成子图中边权最大的边的权值最小可能是多少。

    $nle 10^5,mle 10^6,l_ile 10^9$

    题解:可以证明如果存在一个生成子图满足所有点度数都是奇数,当且仅当所有连通块都有偶数个点。并且可以知道加边一定不会使答案更劣。正解有三种:1.LCT维护最小生成树;2.cdq分治(类似整体二分);3.线段树(类似按时间分治)。都比较神,本人采用了第二种。

    官方题解:http://codeforces.com/blog/entry/21914

    大神的第二种做法的题解:https://www.cnblogs.com/galaxies/p/cf603E.html

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    const int maxn=100010;
    const int maxm=300010;
    int f[maxn],g[maxn],siz[maxn],st[maxn],ans[maxm];
    int n,m,cnt,top;
    struct edge
    {
    	int a,b,c,tim;
    }p[maxm],q[maxm];
    bool cmp(const edge &a,const edge &b)
    {
    	return (a.c==b.c)?(a.tim<b.tim):(a.c<b.c);
    }
    inline void uni(int a,int b)
    {
    	int x=a,y=b,c=0,d=0;
    	while(f[x]!=x)	x=f[x],c++;
    	while(f[y]!=y)	y=f[y],d++;
    	if(x==y)	return ;
    	if(c>d)	swap(x,y),swap(a,b);
    	cnt-=(siz[x]&1)+(siz[y]&1)-((siz[x]+siz[y])&1);
    	siz[y]+=siz[x],f[x]=y;
    	st[++top]=x;
    }
    inline void del(int x)
    {
    	int y=f[x];
    	siz[y]-=siz[x],f[x]=x;
    	cnt+=(siz[x]&1)+(siz[y]&1)-((siz[x]+siz[y])&1);
    }
    void solve(int l,int r,int L,int R)
    {
    	if(l>r)	return ;
    	int mid=(l+r)>>1,i,now=top,MID;
    	for(i=l;i<=mid;i++)	if(p[i].c<=L)	uni(p[i].a,p[i].b);
    	for(i=L;i<=R&&cnt;i++)	if(q[i].tim<=mid)	uni(q[i].a,q[i].b);
    	MID=max(L,i-1);
    	if(!cnt)	ans[p[mid].tim]=q[MID].c;
    	else	ans[p[mid].tim]=-1;
    	while(top>now)	del(st[top--]);
    	for(i=L;i<=MID;i++)	if(q[i].tim<=l)	uni(q[i].a,q[i].b);
    	solve(l,mid-1,MID,R);
    	while(top>now)	del(st[top--]);
    	for(i=l;i<=mid;i++)	if(p[i].c<=L)	uni(p[i].a,p[i].b);
    	solve(mid+1,r,L,MID);
    	while(top>now)	del(st[top--]);
    }
    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;
    	for(i=1;i<=m;i++)	p[i].a=rd(),p[i].b=rd(),p[i].c=rd(),p[i].tim=i,q[i]=p[i];
    	sort(q+1,q+m+1,cmp);
    	for(i=1;i<=n;i++)	f[i]=i,siz[i]=1;
    	for(i=1;i<=m;i++)	p[q[i].tim].c=i;
    	cnt=n;
    	solve(1,m,1,m);
    	for(i=1;i<=m;i++)	printf("%d
    ",ans[i]);
    	return 0;
    }
  • 相关阅读:
    #define中的特殊符号
    c++ windows下计时
    c++内存池
    u3d 场景资源打包
    Unity3d 动态加载材质方法
    Unity3D Shader基础教程
    Unity3D Shader入门指南(一)
    Unreal发展史
    阴影锥(shadow volume)原理与展望
    软硬RAID 和 不常见的RAID
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/8595001.html
Copyright © 2020-2023  润新知