zoukankan      html  css  js  c++  java
  • CF429E Points and Segments

    一、题目

    点此看题

    二、解法

    ( t CF) 远古场的题,感觉思维得到了巨大的锤炼

    因为判断不合法的点只需要考虑端点,所以我们先把端点离散化。

    两种东西选主元,比如我们选红色为主元,假设一个点被线段覆盖了 (cnt) 次,那么合法的充要条件是这个点被红色线段覆盖了 (lfloorfrac{cnt}{2} floor) 或者是 (lceilfrac{cnt}{2} ceil)

    可以根据这个建立网络流模型,相邻两个点连下界为 (lfloorfrac{cnt}{2} floor) 上界为 (lceilfrac{cnt}{2} ceil) 的边,每个边的流量意义就是起点被红色线段覆盖的次数,然后对于区间 ([l,r]) 我们需要决策它是否是红色线段,把 (r+1)(l) 一条容量为 (1) 的边,流过这条边就代表这个区间染红。

    但是网络流跑不过,观察如果 (cnt) 是偶数这个限制为必须有 (frac{cnt}{2}) 条红色线段,(cnt) 是奇数就有点难搞了。我们可以设置辅助变量把奇数的限制归约到偶数限制,如果 (i) 的被覆盖次数为奇数,那么添加一个区间 ([i,i])

    现在把红色线段权值看成 (1),蓝色线段权值看成 (-1),那么每个点的权值都是 (0),对于每个区间我们连边 ([l,r+1]),限制很容易转化成给一个无向图,给每条边定向,要求每个点的入度等于出度。

    那么这就是欧拉回路啊,按路径的方向定向即可,容易证明得到的图每个点的度数为偶数,所以一定有解。

    三、总结

    在转化限制类问题中,两种东西选主元的方法可以把限制转化到一个东西上。

    添加辅助变量的思想真的特别重要!它可以把不同种类的限制规约,能简化限制,经典例子是线性规划添加基向量把问题转成标准型。

    欧拉回路应用积累:构造给边定向的方案使得每个点的入度等于出度。

    #include <cstdio>
    #include <algorithm>
    using namespace std;
    const int M = 500005;
    int read()
    {
    	int x=0,f=1;char c;
    	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
    	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
    	return x*f;
    }
    int n,m,k,tot,f[M],a[M],b[M];
    int l[M],r[M],cur[M],vis[M],ans[M];
    struct edge
    {
    	int v,id,next;
    }e[4*M];
    void add(int u,int v,int id)
    {
    	e[++tot]=edge{v,id,f[u]},f[u]=tot;
    	e[++tot]=edge{u,id,f[v]},f[v]=tot;
    }
    void dfs(int u)
    {
    	while(vis[e[cur[u]].id])
    		cur[u]=e[cur[u]].next;
    	if(!cur[u]) return ;
    	int i=cur[u],v=e[i].v;
    	ans[e[i].id]=u<=v;
    	vis[e[i].id]=1;
    	cur[u]=e[i].next;
    	dfs(v);
    }
    signed main()
    {
    	n=k=read();
    	for(int i=1;i<=n;i++)
    	{
    		l[i]=a[++m]=read();
    		r[i]=a[++m]=read()+1;
    	}
    	sort(a+1,a+1+m);
    	m=unique(a+1,a+1+m)-a-1;
    	for(int i=1;i<=n;i++)
    	{
    		l[i]=lower_bound(a+1,a+1+m,l[i])-a;
    		r[i]=lower_bound(a+1,a+1+m,r[i])-a;
    		b[l[i]]++;b[r[i]]--;
    		add(l[i],r[i],i);
    	}
    	for(int i=1;i<=m;i++)
    	{
    		b[i]+=b[i-1];
    		if(b[i]%2) add(i,i+1,++k);
    	}
    	for(int i=1;i<=m;i++)
    		cur[i]=f[i];
    	for(int i=1;i<=m;i++)
    		if(cur[i]) dfs(i);
    	for(int i=1;i<=n;i++)
    		printf("%d ",ans[i]);
    }
    
  • 相关阅读:
    LightOJ 1132 Summing up Powers(矩阵快速幂)
    hdu 3804 Query on a tree (树链剖分+线段树)
    LightOJ 1052 String Growth && uva 12045 Fun with Strings (矩阵快速幂)
    uva 12304 2D Geometry 110 in 1! (Geometry)
    LA 3263 That Nice Euler Circuit (2D Geometry)
    2013 SCAUCPC Summary
    poj 3321 Apple Tree (Binary Index Tree)
    uva 11796 Dog Distance (几何+模拟)
    uva 11178 Morley's Theorem (2D Geometry)
    动手动脑
  • 原文地址:https://www.cnblogs.com/C202044zxy/p/15219917.html
Copyright © 2011-2022 走看看