[Cnoi2019]ファンタジーランド(LCTメンテナンス最大スパニングツリー+チェアマンツリー/ブロック)

記事のディレクトリ

題名

解決

NNnポイントツリーにはn-1n-1がありますn1つのエッジ
一般に、フォレストにはいくつかのポイントがあります-エッジの数=木の数

無向グラフからスパニングツリーをランダムに生成してフォレストを形成します
。クエリ内の接続されたブロックの数は、フォレスト内のツリーの数、つまりフォレスト内のポイントの数になります-フォレスト内のエッジの数=接続されているブロックの数

次に、LCTLCTを使用できますL C Tはスパニングツリーを動的に維持し、rrを要求しますr小さいものから大きいものへの並べ替え、チェアツリークエリ

LCTLCT L C Tはエッジの権利を維持するのは簡単でなく、エッジを接続する仮想ポイントを作成するだけです

以下のための[L、R]、[L、R][ l r ]には、入力時間がシーケンスの決定に使用されると仮定して、エッジが含まれます。
エッジiiの場合i、追加後にリングを形成できない場合は、直接追加します。リングを形成する場合は、リングの最初のエッジを削除
て、後のエッジが[l、r] [l、r]に存在する可能性を高めます。][ l r ]rrrは増加しています

⚡:自己ループがあります!

コード

#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;
} 

おすすめ

転載: blog.csdn.net/Emm_Titan/article/details/112546764