线段树分治,比起 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);
}