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]);
    }
    
  • 相关阅读:
    代码对比软件——code compare
    IAR调试和keil调试的一点小区别
    谷访问歌助手
    X86架构的寄存器
    ant-design-pro
    js 闭包 作用域
    《三体》总结
    如何通过SQL注入盗取数据库信息
    《看见》总结
    《欲望的演化》总结
  • 原文地址:https://www.cnblogs.com/C202044zxy/p/15219917.html
Copyright © 2011-2022 走看看