• 6491. 【GDOI2020模拟03.04】铺路


    题目描述


    题解

    结论:存在一种合法方案当且仅当所有联通块大小为偶数

    证明:随便做一个生成树,然后每次断掉一条两边大小都为偶数的边

    断完之后变成若干棵树,每棵树大小为偶数且每条边两侧的块大小都为奇数

    选取当前的所有边,若存在度数为偶数的点,那么总点数为偶数*断开后块大小(奇数)+1,结果为奇数,与条件矛盾

    同时还有一个性质,改变断边的顺序不会影响到最终断边方案

    因为每次断掉的大小都为偶数,不会使原来两侧是大小是奇数的加上后变为偶数


    从后往前做,先假设所有边都给出

    把边从小到大排序做生成树,直到全部块都为偶数

    那么最后加入的那条边的长度即为答案

    因为答案=断边之后剩下的最大边,而加入的最后一条边会把两个奇数块合并,也就是说必然会保留

    把-1看成+inf,答案显然单调不增,反着做就是单调不减

    那么对于<=当前答案的边就可以全部丢到图里备选,显然不会使奇偶性改变or使答案变小

    从后往前线段树分治,对于一个叶子节点如果图不满足条件就把未加的边从小到大加

    经过一条边就把它丢到[出现位置,当前位置-1]处(边遍历边修改)

    答案就是当前丢到图中的最大边权

    (至于为什么从小到大丢就可以最优……应该是和生成树一类的吧,也许可以用拟阵证明)

    code

    #include <bits/stdc++.h>
    #define fo(a,b,c) for (a=b; a<=c; a++)
    #define fd(a,b,c) for (a=b; a>=c; a--)
    #define ll long long
    #define file
    using namespace std;
    
    struct type{
    	int x,y,s,id,X,Y,S;
    } a[300001];
    int ans[300001],fa[100001],d[100001],size[100001],n,m,i,j,k,l,sum,L;
    vector<int> tr[1200001];
    
    bool cmp(type a,type b)
    {
    	return a.s<b.s;
    }
    
    int gf(int t)
    {
    	while (fa[t]!=t) t=fa[t];
    	return t;
    }
    
    void swap(int &x,int &y)
    {
    	int z=x;x=y;y=z;
    }
    
    void link(int id)
    {
    	int x=a[id].x,y=a[id].y;
    	
    	x=gf(x);y=gf(y);
    	if (x==y) {a[id].X=0;return;}
    	
    	if (d[x]>d[y]) swap(x,y);
    	a[id].X=x,a[id].Y=y;
    	fa[x]=y;
    	
    	a[id].S=d[x]==d[y];
    	d[y]+=d[x]==d[y];
    	
    	sum-=(size[x]&1)+(size[y]&1);
    	size[y]+=size[x];
    	sum+=(size[y]&1);
    }
    
    void cut(int id)
    {
    	if (!a[id].X) return;
    	
    	int x=a[id].X,y=a[id].Y;
    	
    	fa[x]=x;
    	d[y]-=a[id].S;
    	
    	sum-=(size[y]&1);
    	size[y]-=size[x];
    	sum+=(size[x]&1)+(size[y]&1);
    }
    
    void change(int t,int l,int r,int x,int y,int s)
    {
    	if (x>y) return;
    	
    	int mid=(l+r)/2;
    	
    	if (x<=l && r<=y)
    	{
    		tr[t].push_back(s);
    		return;
    	}
    	
    	if (x<=mid)
    	change(t*2,l,mid,x,y,s);
    	if (mid<y)
    	change(t*2+1,mid+1,r,x,y,s);
    }
    
    void dfs(int t,int l,int r)
    {
    	int mid=(l+r)/2,i,L2,N=tr[t].size();
    	
    	fo(i,0,N-1) link(tr[t][i]);
    	
    	if (l==r)
    	{
    		L2=L;
    		while (L<=m && sum)
    		{
    			if (a[L].id<=l)
    			link(L),change(1,1,m,a[L].id,l-1,L);
    			++L;
    		}
    		
    		if (sum)
    		ans[l]=-1;
    		else
    		ans[l]=a[L-1].s;
    		
    		fd(i,L-1,L2) if (a[i].id<=l) cut(i);
    		fd(i,N-1,0) cut(tr[t][i]);
    		return;
    	}
    	
    	dfs(t*2+1,mid+1,r);
    	dfs(t*2,l,mid);
    	
    	fd(i,N-1,0) cut(tr[t][i]);
    }
    
    int main()
    {
    	freopen("road.in","r",stdin);
    	#ifdef file
    	freopen("road.out","w",stdout);
    	#endif
    	
    	scanf("%d%d",&n,&m);
    	if (n&1)
    	{
    		fo(i,1,m) printf("-1
    ");
    		return 0;
    	}
    	fo(i,1,m)
    	scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].s),a[i].id=i;
    	
    	fo(i,1,n) fa[i]=i,d[i]=size[i]=1;
    	
    	sort(a+1,a+m+1,cmp);
    	
    	sum=n;L=1;
    	dfs(1,1,m);
    	
    	fo(i,1,m)
    	printf("%d
    ",ans[i]);
    	
    	fclose(stdin);
    	fclose(stdout);
    	
    	return 0;
    }
    
  • 相关阅读:
    借助baidu的jsonp接口,做一个自己的候选词组件
    Cannot set property 'innerHTML' of null
    Win下端口占用问题:OSError: [WinError 10013] 以一种访问权限不允许的方式做了一个访问套接字的尝试
    一文读懂ES6(附PY3对比)
    Wireshark:couldn't run dumpcap in child process(附带Linux下探索过程)
    一个模块导入的简单小测试
    万物互联之~网络编程加强篇
    网罗天下之~正则表达
    (转)RTSP协议详解
    (转)HLS协议,html5视频直播一站式扫盲
  • 原文地址:https://www.cnblogs.com/gmh77/p/12431929.html
Copyright © 2020-2023  润新知