[Cnoi2019] Fantasy Land (LCT Maintenance Maximum Spanning Tree + Chairman Tree/Block)

Article Directory

title

solution

A nnn points tree hasn - 1 n-1n1 edge In
general, for the forest, there is anumber of points-the number of edges = the number of trees

Randomly generate a spanning tree from the undirected graph to form a forest
. The number of connected blocks in the query becomes the number of trees in the forest , that is, the number of points in the forest-the number of edges in the forest = the number of connected blocks

Then you can use LCT LCTL C T dynamically maintains the spanning tree, and will askrrr sorted from small to large, chair tree query

L C T LCT L C T is not easy to maintain edge rights, just create virtual points to connect edges

For [l, r] [l, r][l,r ] includes the edges, assuming that the input time is used to determine the sequence.
For edgeiii , if you cannot form a ring after adding, add it directly; if a ring is formed, deletethe earliest edge on the ring,
so that the later edges are more likely to exist in[l, r] [l,r][l,r] r r r is increasing

⚡: There is a self-loop!

code

#include <cstdio>
#include <iostream>
using namespace std;
#define maxn 400005
#define inf 0x7f7f7f7f
struct node {
    
    
	int u, v;
}edge[maxn];

struct LCT {
    
    
	int f, rev, val, minn;
	int son[2];
}tree[maxn];
int st[maxn];

bool notroot( int x ) {
    
    
	return tree[tree[x].f].son[0] == x || tree[tree[x].f].son[1] == x;
}

void update( int x ) {
    
    
	tree[x].minn = min( tree[x].val, min( tree[tree[x].son[0]].minn, tree[tree[x].son[1]].minn ) );
}

void reverse( int x ) {
    
    
	swap( tree[x].son[0], tree[x].son[1] );
	tree[x].rev ^= 1;
} 

void pushdown( int x ) {
    
    
	if( ! tree[x].rev ) return;
	reverse( tree[x].son[0] );
	reverse( tree[x].son[1] );
	tree[x].rev = 0;
}

void rotate(int x) {
    
     
    int fa = tree[x].f, Gfa = tree[fa].f;
	int k = tree[fa].son[1] == x;
	if( notroot( fa ) )
		tree[Gfa].son[tree[Gfa].son[1] == fa] = x;
	tree[x].f = Gfa;
	tree[fa].son[k] = tree[x].son[k ^ 1];
	if( tree[x].son[k ^ 1] )
		tree[tree[x].son[k ^ 1]].f = fa;
	tree[x].son[k ^ 1] = fa;
	tree[fa].f = x;
	update( fa );
	update( x );
}

void splay( int x ) {
    
    
	int top = 0, y = x;
	st[++ top] = y;
	while( notroot( y ) ) st[++ top] = y = tree[y].f;
	while( top ) pushdown( st[top --] );
	while( notroot( x ) ) {
    
    
		int fa = tree[x].f, Gfa = tree[fa].f;
		if( notroot( fa ) ) 
			( ( tree[Gfa].son[0] == fa ) ^ ( tree[fa].son[0] == x ) ) ? rotate( x ) : rotate( fa );
		rotate( x );
	}
	update( x );
}

void access( int x ) {
    
    
	for( int son = 0;x;son = x, x = tree[x].f ) {
    
    
		splay( x );
		tree[x].son[1] = son;
		update( x );
	}
}

void makeroot( int x ) {
    
    
	access( x );
	splay( x );
	swap( tree[x].son[0], tree[x].son[1] );
	tree[x].rev ^= 1;
}

void split( int x, int y ) {
    
    
	makeroot( x );
	access( y );
	splay( y );
}
	
int findroot( int x ) {
    
    
	access( x );
	splay( x );
	while( tree[x].son[0] ) x = tree[x].son[0];
	splay( x );
	return x;
}

void link( int x, int y ) {
    
    
	split( x, y );
	tree[x].f = y;
}

void cut( int x, int y ) {
    
    
	split( x, y );
	tree[x].f = tree[y].son[0] = 0;
}

int ask( int x, int y ) {
    
    
	split( x, y );
	return tree[y].minn;
}

struct SegmentTree {
    
    
	int cnt, l, r;
}seg[maxn * 20];
int tot;
int rt[maxn];

void modify( int &num, int l, int r, int pos, int v ) {
    
    
	int x = ++ tot;
	seg[x].l = seg[num].l, seg[x].r = seg[num].r, seg[x].cnt = seg[num].cnt + v, num = x;
	if( l == r ) return;
	int mid = ( l + r ) >> 1;
	if( pos <= mid ) modify( seg[num].l, l, mid, pos, v );
	else modify( seg[num].r, mid + 1, r, pos, v );
}

int query( int num, int l, int r, int L, int R ) {
    
    
	if( L <= l && r <= R ) return seg[num].cnt;
	int mid = ( l + r ) >> 1, ans = 0;
	if( L <= mid ) ans += query( seg[num].l, l, mid, L, R );
	if( mid < R ) ans += query( seg[num].r, mid + 1, r, L, R );
	return ans;
}

int n, m, Q, t, last;

void get( int &l, int &r ) {
    
    
	if( t ) l = ( l + last ) % m + 1, r = ( r + last ) % m + 1;	
	if( l > r ) swap( l, r );
}

int main() {
    
    
	scanf( "%d %d %d %d", &n, &m, &Q, &t );
	for( int i = 0;i <= n;i ++ ) tree[i].val = tree[i].minn = inf;
	for( int i = 1;i <= m;i ++ ) {
    
    
		scanf( "%d %d", &edge[i].u, &edge[i].v );
		tree[i + n].val = tree[i + n].minn = i;
	}
	for( int i = 1;i <= m;i ++ ) {
    
    
		int u = edge[i].u, v = edge[i].v;
		rt[i] = rt[i - 1];
		if( u == v ) continue;
		modify( rt[i], 1, m, i, 1 );
		if( findroot( u ) == findroot( v ) ) {
    
    
			int pos = ask( u, v );
			cut( edge[pos].u, pos + n );
			cut( edge[pos].v, pos + n );
			modify( rt[i], 1, m, pos, -1 );
		}
		link( u, i + n );
		link( v, i + n );
	}
	while( Q -- ) {
    
    
		int l, r;
		scanf( "%d %d", &l, &r );
		get( l, r );
		last = n - query( rt[r], 1, m, l, r );
		printf( "%d\n", last );
	}
	return 0;
} 

Guess you like

Origin blog.csdn.net/Emm_Titan/article/details/112546764