ABC155F - Perils in Parallel

简述题意 给你N个数对 表示坐标与状态(0/1), M个操作,给定一个区间,区间内的坐标的状态翻转

思路:看到区间修改,很容易想到差分,对数对sort,每个a_i与a_i-1异或构造差分数组b,每次对[l,r]区间操作时,只需要将b[l]与b[r+1]对1异或操作就行了

那么我们如何判断哪些操作需要选择呢,我们可以将每一段有关联的区间操作连边建树,我们知道,当某个点为1时,要异或为0必须操作奇数次,统计每一组操作中差分数组为1的情况,如果有偶数个差分数组为1的情况,那么一定能使每个点变为0,因为每次操作能且只能操作2个点,2个点配对为一组

那我们如何建呢,用并查集建一个生成树,统计每一棵树上的个数到树根上,这样判断树根就可以判断是否有解

如果有解,那我们从每一个树根出发跑dfs,对每个点,如果其子树(包括自己)的差分数组为1的个数为奇数,那么该点就必须进行一次操作,将他与他的父节点转变一次,使得其子树的差分数组为1的个数为偶数,那么必定通过操作将每个点化为0,有点类似点分治找重心的过程,使用后序操作,保证每一个点最后都是0,因为每个点的siz为奇数的话,其子树节点已经全为0,他自身就需要改变,siz为偶数的话,他就是一个与其他奇数节点配对的点,不需要改变,或者说他是配对的1,也就是不需要操作,举个小例子,1-1 0-1,第一个的前驱不需要改变,第二个的需要

#include<bits/stdc++.h>
using namespace std;
#define lowbit(x) ((x)&(-x))
typedef pair<int, int> pii;
typedef long long LL;

const int maxm = 1e5+5;

vector<pii> G[maxm];
vector<int> ans;
pii a[maxm];
int b[maxm], pos[maxm], cnt[maxm], siz[maxm], fa[maxm];

int Find(int x) {
    return fa[x] == x?x:fa[x] = Find(fa[x]);
}

void dfs(int u, int fa, int id) {
    siz[u] = b[u];
    for(auto i : G[u]) {
        int v = i.first;
        if(v == fa) continue;
        dfs(v, u, i.second);
        siz[u] += siz[v];
    }
    if(siz[u] & 1) ans.push_back(id);
}

void run_case() {
    int n, m;
    cin >> n >> m;
    for(int i = 1; i <= n; ++i) cin >> a[i].first >> a[i].second;
    sort(a+1, a+1+n);
    for(int i = 1; i <= n; ++i) pos[i] = a[i].first;
    for(int i = 1; i <= n+1; ++i) {
        fa[i] = i;
        b[i] = a[i].second ^ a[i-1].second;
    }
    for(int i = 1; i <= m; ++i) {
        int l, r, tl, tr;
        cin >> l >> r;
        l = lower_bound(pos+1, pos+1+n, l) - pos;
        r = upper_bound(pos+1, pos+1+n, r) - pos;
        tl = Find(l), tr = Find(r);
        if(tl == tr) continue;
        fa[tl] = tr;
        G[l].push_back(make_pair(r, i));
        G[r].push_back(make_pair(l, i));
    }
    for(int i = 1; i <= n+1; ++i) if(b[i]) cnt[Find(i)]++;
    for(int i = 1; i <= n+1; ++i)
        if(Find(i) == i && (cnt[i]&1)) {
            cout << "-1";
            return;
        }
    for(int i = 1; i <= n+1; ++i) {
        if(Find(i) == i) dfs(i, 0, 0);
    }
    sort(ans.begin(), ans.end());
    cout << ans.size() << "\n";
    for(auto i : ans) cout << i << " ";
}

int main() {
    ios::sync_with_stdio(false), cin.tie(0);
    //cout.setf(ios_base::showpoint);cout.precision(8);
    run_case();
    cout.flush();
    return 0;
}
View Code

 

posted @ 2020-02-17 20:51  GRedComeT  阅读(315)  评论(0编辑  收藏  举报