AT4831 [ABC155F] Perils in Parallel 生成树

题意:

戳这里

分析:

首先我们先把区间操作转化一下,因为区间操作的复杂度太高

我们把每一位上的值记为它和它前一位的异或值

这样 \([l,r]\) 的区间翻转等价于 \(l,r+1\) 的单点异或,而我们的目标还是使得所有位置上的值为 \(0\)

像这样的点对关系我们可以看成 \(l,r+1\) 之间连接了一条无向边,我们要做的就是选择一些边,将两端的点值取反,使得每一个点的值为 0

然后我们建出图之后会发现,这是一个不连通的一般图,但是我们发现可以将这幅图转化为一些森林,因为如果选中的边成环了那么等价于没有选,所以每一个连通块都是一棵树,那么我们的问题转化为对于每一棵树选一些边,最后使得树上所有点的值为 \(0\) ,直接树形DP

对于节点 \(u\) 如果他的一个儿子值为 \(1\) 那么这条边必须选,同时对 \(u\)\(v\) 的值取反,如果为 \(0\) 那么不选

最后如果根节点的值为 \(1\) 那么无解

tip: 因为区间操作转化为单点操作的时候会出现 \(n+1\) 点,但实际上 \(n+1\) 点的点值不存在,所以它为 \(0,1\) 都不影响结果,所以我们可以钦定 \(n+1\) 所在的连通块以 \(n+1\) 为根,不论结果如何不用管

代码:

#include<bits/stdc++.h>
#define pii pair<int,int>
#define mk(x,y) make_pair(x,y)
#define fir first
#define sec second
#define inl inline
#define reg register
#define pb push_back

using namespace std;

namespace zzc
{
    inl int read()
    {
        int x=0,f=1;char ch=getchar();
        while(!isdigit(ch)) {if(ch=='-')f=-1;ch=getchar();}
        while(isdigit(ch)) {x=x*10+ch-48;ch=getchar();}
        return x*f;
    }

    const int maxn = 2e5+5;
    int n,m,cnt;
    pii p[maxn];
    int pos[maxn],fa[maxn],head[maxn];
    bool vis[maxn],sta[maxn];
    vector<int> ans;

    struct edge
    {
        int to,nxt,id;
    }e[maxn<<2];

    inl void add(int u,int v,int w)
    {
        e[++cnt].to=v;
        e[cnt].id=w;
        e[cnt].nxt=head[u];
        head[u]=cnt;
    }

    int find(int x) {return fa[x]==x?x:fa[x]=find(fa[x]);}
    
    inl bool connect(int x,int y)
    {
        int fx=find(x),fy=find(y);
        if(fx==fy) return true;
        fa[fy]=fx;
        return false;
    }

    bool dfs(int u)
    {
        bool res=sta[u];
        vis[u]=true;
        for(int i=head[u];i;i=e[i].nxt)
        {
            int v=e[i].to;
            if(vis[v]) continue;
            bool tmp=dfs(v);
            if(tmp) ans.pb(e[i].id);
            res^=tmp;
        }
        return res;
    }

    void work()
    {
        int l,r;
        n=read();m=read();
        for(int i=1;i<=n+1;i++) fa[i]=i;
        for(int i=1;i<=n;i++) p[i].fir=read(),p[i].sec=read();
        sort(p+1,p+n+1);
        for(int i=1;i<=n;i++) pos[i]=p[i].fir,sta[i]=p[i].sec;
        for(int i=n;i;i--) sta[i]^=sta[i-1];
        for(int i=1;i<=m;i++)
        {
            l=read();r=read();
            l=lower_bound(pos+1,pos+n+1,l)-pos;
            r=upper_bound(pos+1,pos+n+1,r)-pos;
            if(!connect(l,r)) add(l,r,i),add(r,l,i);
        }
        dfs(n+1);
        for(int i=1;i<=n;i++)
        {
            if(vis[i]) continue;
            if(dfs(i))
            {
                puts("-1");
                return ;
            }
        }
        sort(ans.begin(),ans.end());
        printf("%d\n",ans.size());
        for(int i=0,j=ans.size();i<j;i++) printf("%d ",ans[i]);
    }

}

int main()
{
    zzc::work();
    return 0;
}

posted @ 2021-01-26 13:23  youth518  阅读(63)  评论(0)    收藏  举报