zoukankan      html  css  js  c++  java
  • CF576E Painting Edges

    CF576E Painting Edges

    线段树分治,比起 P5787 二分图 这道题多了一个颜色,限制。那么考虑消除。

    我们可以选择每个颜色单独讨论,但是显然是假的。

    那么我们可以在失败操作的时候考虑把当前不能合并的边改成这条边之前的颜色。

    比如{a,b,c}其中有边{a,c}{a,b}(两个红色)然后新加入了 {b,c}(也是红色)我们发现他不行。

    因为这时候{b,c}边是无色的,那么我们把这次操作的颜色也改成无色的就好了,剩下的就是线段树分治板子。

    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <vector>
    #include <stack>
    
    using namespace std;
    
    typedef int ll;
    typedef pair<ll, ll> pll;
    const ll MAXN = 5e5+10;
    
    struct edge {
        ll x, y;
    } E[MAXN];
    
    struct kk {
        ll x, y, add, col;
    };
    
    struct nod {
        ll l, r;
        vector <ll> q;
    } t[MAXN << 2];
    
    stack <kk> st;
    ll que[MAXN], N, M, K, Q, pos[MAXN], col[MAXN], nowcol, fa[55][MAXN << 1], siz[55][MAXN << 1];
    
    void build(ll, ll, ll);
    void dfs(ll);
    ll find_(ll, ll);
    void ins(ll, ll, ll, ll);
    void onion(ll, ll, ll);
    
    int main() {
        scanf("%d%d%d%d", &N, &M, &K, &Q);
        for (ll i = 1; i <= M; i++) scanf("%d%d", &E[i].x, &E[i].y), pos[i] = Q + 1;
        for (ll i = 1; i <= Q; i++) scanf("%d%d", que+i, col+i);
        build(1, 1, Q);
        for (ll i = 1; i <= K; i++) 
    		for (ll j = 1; j <= N << 1; j++) 
    			siz[i][j] = 1, fa[i][j] = j;
        for (ll i = Q; i; i--) {
            ll tem = que[i];
            if (i < pos[tem] - 1) ins(1, i + 1, pos[tem] - 1, i);
            pos[tem] = i;
    	}
        memset(pos, 0, sizeof(pos));
        dfs(1);
        return 0;
    }
    
    void dfs(ll node) {
        ll l = t[node].l, r = t[node].r;
        unsigned int lst = st.size();
        for (unsigned int i = 0; i < t[node].q.size(); i++) {
            ll now = t[node].q.at(i);
            ll id = que[now], c = col[now];
            if (!c) continue;
            onion(c, find_(E[id].x + N, c), find_(E[id].y, c));
            onion(c, find_(E[id].x, c), find_(E[id].y + N, c));
        }
        if (l == r) {
            ll id = que[l], c = col[l];
            if (find_(E[id].x, c) == find_(E[id].y, c)) puts("NO"), col[l] = pos[id];
            else puts("YES"), pos[id] = col[l];
        	return;
    	}
        dfs(node << 1);
        dfs(node << 1 | 1);
        while (st.size() > lst) {
        	kk tem = st.top(); st.pop();
    		siz[tem.col][tem.y] -= tem.add;
    		fa[tem.col][tem.x] = tem.x;
        }
    }
    
    void onion(ll c, ll x, ll y) {
        if (x == y) return;
        if (siz[c][x] > siz[c][y]) swap(x, y);
        st.push({x, y, siz[c][x], c});
        fa[c][x] = y;
        siz[c][y] += siz[c][x];
    }
    
    ll find_(ll x, ll c) {while (x ^ fa[c][x]) x = fa[c][x]; return x;}
    
    void ins(ll node, ll a, ll b, ll pos) {
    	if (b < t[node].l || t[node].r < a) return;
        if (a <= t[node].l && t[node].r <= b) {
            t[node].q.push_back(pos);
            return;
        }
        ll mid = (t[node].l + t[node].r) >> 1;
        if (a <= mid) ins(node << 1, a, b, pos);
        if (mid < b) ins(node << 1 | 1, a, b, pos);
    }
    
    void build(ll node, ll l, ll r) {
        t[node].l = l;
        t[node].r = r;
        t[node].q.clear();
        if (l == r) return;
        ll mid = (l + r) >> 1;
        build(node << 1, l, mid);
        build(node << 1 | 1, mid+1, r);
    }
    
    
  • 相关阅读:
    ChinaUnionPay、Visa和MasterCard信用卡号验证
    使用Aspose.Cells 过程中用过的知识(转)
    在网页中回车默认按钮
    求素数算法
    通过jQuery的attr修改onclick(转)
    子页面js代码改变父页面iframe的大小(转)
    考虑线程安全但效率不高的单例C++代码
    Linux信号量摧毁/销毁
    WCF、WPF、Silverlight和区别(转)
    不考虑线程安全的初级单例C++代码
  • 原文地址:https://www.cnblogs.com/Gensokyo-Alice/p/13784579.html
Copyright © 2011-2022 走看看