題名
解決
NNnポイントツリーにはn-1n-1がありますn−1つのエッジ
一般に、フォレストにはいくつかのポイントがあります-エッジの数=木の数
無向グラフからスパニングツリーをランダムに生成してフォレストを形成します
。クエリ内の接続されたブロックの数は、フォレスト内のツリーの数、つまりフォレスト内のポイントの数になります-フォレスト内のエッジの数=接続されているブロックの数
次に、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;
}