2020 Niuke summer multi school training camp (Session 8) A All Star

Topic connection

Each player has some fans. The condition for a fan to watch a player's game is

  • He likes the player

  • People who like the same player like this player.

The relationship between players and fans can be changed dynamically. Ask how many players are invited to play after each change so that all fans can watch the game.

The change is that for the two numbers of b a nd a, b is the fan number and a is the player number. If b is a fan of a, now b is not a fan of a, on the contrary, b becomes a fan of A.

It is equivalent to segment tree divide and conquer. For each query, throw it into each leaf node of the segment tree, and then record the interval of each relationship. Use segment tree interval coverage.

cnt represents the number of Unicom blocks, cnta represents the number of individual players, and cntb represents the number of individual fans,

If cntb is not 0, output - 1, otherwise output cnt - cnta

The connection block is represented by the joint query set. Each time the line segment tree is pushed down, the current joint query set status should be recorded, and the data should be restored when returning.

At this time, the merge set cannot be compressed by path, and heuristic merging is required when merging the merge set, that is, small sets are connected to large sets.

#include<bits/stdc++.h>
using namespace std;
const int N = 4e5+100;
typedef pair<int,int>P;
struct recv{
	int a,asz,b,bsz;
	int cnt,cnta,cntb;
};
struct node{
	int l,r; // left and right 
	vector<P>e;
	vector<recv> rec;
}tr[N<<2];
int n,m,q,f[N<<1],cnt,cnta,cntb,ans[N<<1],sz[N<<1];

map<int,int>mp[N];
int find(int k){
	if (f[k] == k) return k;
	return find(f[k]);
}

void build(int now, int l, int r){
	tr[now].l = l; tr[now].r = r;
	tr[now].e.clear();
	tr[now].rec.clear();
	if (l == r) return;
	int mid = (l + r) >> 1;
	build(now << 1, l, mid);
	build(now << 1 | 1, mid+1, r);
}
void update(int now, int l, int r, P p){
	if(l <= tr[now].l &&  r >= tr[now].r) {
		tr[now].e.push_back(p);
		return;
	}
	int mid = (tr[now].l + tr[now].r) >> 1;
	if (l <= mid) update(now << 1, l, r, p);
	if (r >= mid + 1) update(now << 1 | 1,l, r, p);
}

void solve(int now){
	int a,b,len = 0;
	recv tmp;
	for (auto it: tr[now].e){
		a = find(it.first); b = find(it.second);
		if (a == b) continue;
		tmp.cnt = cnt; tmp.cnta = cnta; tmp.cntb = cntb;
		cnt--;
		if (sz[a] == 1) cnta--;
		if (sz[b] == 1) cntb--;
		if (sz[a] < sz[b]) swap(a,b);
		tmp.a = a; tmp.b = b;
		tmp.asz = sz[a];
		tmp.bsz = sz[b];
		f[b] = a;
		sz[a] += sz[b];
		tr[now].rec.push_back(tmp);
		len++;
	}
	if (tr[now].l == tr[now].r){
		if (cntb != 0){
			ans[tr[now].l] = -1;
		} else {
			ans[tr[now].l] = cnt - cnta;
		}
	} else {
		solve(now << 1);
		solve(now << 1 | 1);
	}
	for (int i = len-1; i >= 0; --i){
		tmp = tr[now].rec[i];
		cnt = tmp.cnt;
		cnta = tmp.cnta;
		cntb = tmp.cntb;
		f[tmp.a] = tmp.a;
		f[tmp.b] = tmp.b;
		sz[tmp.a] = tmp.asz;
		sz[tmp.b] = tmp.bsz;
	}
}

void prework(){
	int a,b,k;
	// a is player  b is fan
	scanf("%d%d%d",&n,&m,&q);
	build(1,1,q+1);
	for (int i = 1; i <= n; ++i){
		scanf("%d",&k);
		for (int j = 1; j <= k; ++j){
			scanf("%d",&b);	
			mp[i][b] = 1;
		}
	}
	for (int i = 2; i <= q + 1; ++i){
		scanf("%d%d",&b,&a);
		if (mp[a][b] == 0){
			mp[a][b] = i;
		} else {
			update(1, mp[a][b], i-1,P{a,b+n});
			mp[a][b] = 0;
		}
	}
	for (int i = 1; i <= n; ++i){
		for (auto it: mp[i]){
			if (it.second){
				update(1, it.second, q+1, P{i, it.first+n});
			}
		}
	}
	cnt = n+m;
	cnta = n; cntb = m;
	for (int i = 0; i <= cnt; ++i){
		f[i] = i;
		sz[i] = 1;
	}
}
int main(){
	prework();	
	solve(1);
	for (int i = 2; i <= q+1; ++i)
		printf("%d\n",ans[i]);
	return 0;
}

Tags: data structure

Posted by cueball2000uk on Fri, 13 May 2022 15:35:36 +0300