The best in the world txdy

description

djq_cpp is the best in the world.
djq_cpp gives you an undirected graph with n points and m edges (no double edge self ring), and the dot label is 1 ∼ n. He wants to test you,
How many pairs of integer pairs (l, r) satisfy:
• 1 ≤l ≤r ≤n
• if the points in the interval [l, r] and the edges between them are retained, and the other points and edges are thrown away, then the left one
The graph is just a chain.
Note: the chain must be a connected graph. In particular, the graph of a point is also a chain.

Input
The first line contains two nonnegative integers n, m.
Next m lines, each line has two positive integers u, v(1 ≤ u, v ≤ n, u ̸= v) , which means there is an edge between u and V.
Ensure that the graph has no double edge self ring.

Output
Output an integer representing the answer.

Sample
Input
3 3
1 2
2 3
3 1
Output
5
Explanation
(1, 1), (1, 2), (2, 2), (2, 3), (3, 3) are qualified integer pairs.

Constraint
For 10% of the data, n, m ≤ 100.
For 20% of the data, n, m ≤ 1000.
For 60% of the data, n, m ≤ 50000.
For the other 10% data, ensure that the degree of each point is ≤ 2.
For 100% data, 1 ≤ n ≤ 250000, 0 ≤ m ≤ 250000.

solution

First, the necessary conditions for the chain are clear

  • Points minus edges = 1 =1 =1
  • exannulate
  • Degrees per point ≤ 2 \le 2 ≤2

The positive solution is to find auxiliary tools to judge the point [ l , r ] [l,r] Do all edges in [l,r] satisfy all the above conditions

In fact, the three conditions can be guaranteed separately and then combined

Double finger needling

Consider the right endpoint of the enumeration point interval r r r

Then find satisfaction [ l , r ] [l,r] The degrees of each point in [l,r] are ≤ 2 \le 2 ≤ 2 min l l l. Record as f [ r ] f[r] f[r]

Obviously with r r Right shift of r, l l l it only gets bigger, not smaller

  • Specifically, use degrees d i d_i di, right endpoint each time + 1 +1 +After 1, add all of the new right endpoint connections [ l , r + 1 ] [l,r+1] [l,r+1], and judge whether the degree of edge connecting two points exceeds 2 2 2. If it exceeds, select to move the left end point to the right and break all connected edges of the original left end point until the degree does not exceed 2 2 2 to stop the left endpoint moving right

Similarly, double finger acupuncture

Consider enumerating right endpoints r r r

Then find satisfaction [ l , r ] [l,r] The smallest of acyclic after all edges in [l,r] are added l l l. Record as g [ r ] g[r] g[r]

Obviously with r r Right shift of r, l l l it only gets bigger, not smaller

  • Specifically, it is essentially the same as the maintenance degree, but it involves the dynamic change of edges, so we have to use the dynamic tree LCT \text{LCT} After LCT, it is judged that the two points connected by the edge of the new right end point are already connected. If this edge is added, a ring will be formed. Move the left end point to the right and break all the connected edges of the original left end point. All this is LCT \text{LCT} LCT's template session

In order to meet the above two conditions, the real left endpoint is l = max ⁡ ( g [ r ] , f [ r ] ) l=\max(g[r],f[r]) l=max(g[r],f[r])

Finally, it must be the connectivity of the same chain

Number of edges required minus number of points = 1 =1 =1. You can use the line segment tree to maintain the minimum value of the number of edges minus the number of points, and then record the number of the minimum value

  • Specifically, for each right endpoint r r r. Segment tree leaf node l l l means [ l , r ] [l,r] After all edges in [l,r] interval are added, the number of edges minus the minimum number of points. In terms of writing, the line segment tree is written together with the judgment of acyclic

The hard LCT people in the examination room are really strong

code

#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
#define maxn 250005
vector < int > G[maxn];
int n, m;
int f[maxn], d[maxn];

namespace LCT {
	struct node { int son[2], f, rev; }t[maxn];
	int s[maxn];
	
	bool isroot( int x ) { return t[t[x].f].son[0] == x or t[t[x].f].son[1] == x; }
	
	void rotate( int x ) {
		int fa = t[x].f, Gfa = t[fa].f, k = t[fa].son[1] == x;
		if( isroot( fa ) )
			t[Gfa].son[t[Gfa].son[1] == fa] = x;
		t[x].f = Gfa;
		t[fa].son[k] = t[x].son[k ^ 1];
		if( t[x].son[k ^ 1] ) t[t[x].son[k ^ 1]].f = fa;
		t[x].son[k ^ 1] = fa;
		t[fa].f = x;
	}
	
	void reverse( int x ) {
		swap( t[x].son[0], t[x].son[1] );
		t[x].rev ^= 1;
	}
	
	void pushdown( int x ) {
		if( t[x].rev ) {
			if( t[x].son[0] ) reverse( t[x].son[0] );
			if( t[x].son[1] ) reverse( t[x].son[1] );
			t[x].rev = 0;
		}
	}
	
	void splay( int x ) {
		int top = 0, y = x;
		s[++ top] = x;
		while( isroot( y ) ) s[++ top] = y = t[y].f;
		while( top ) pushdown( s[top --] );
		while( isroot( x ) ) {
			int fa = t[x].f, Gfa = t[fa].f;
			if( isroot( fa ) )
				( t[Gfa].son[0] == fa ) ^ ( t[fa].son[0] == x ) ? rotate( x ) : rotate( fa );
			rotate( x );
		}
	}
	
	void access( int x ) {
		for( int son = 0;x;son = x, x = t[x].f ) {
			splay( x );
			t[x].son[1] = son;
		}
	}
	
	void makeroot( int x ) {
		access( x );
		splay( x );
		reverse( x );
	}
	
	void split( int x, int y ) {
		makeroot( x );
		access( y );
		splay( y );
	}
	
	int findroot( int x ) {
		access( x );
		splay( x );
		while( t[x].son[0] ) { pushdown( x ); x = t[x].son[0]; }
		splay( x );
		return x;
	}
	
	void link( int x, int y ) {
		makeroot( x );
		if( findroot( y ) == x ) return;
		else t[x].f = y;
	}
	
	void cut( int x, int y ) {
		makeroot( x );
		access( y );
		splay( y );
		t[y].son[0] = t[x].f = 0;
	}
	
	bool connected( int x, int y ) {
		makeroot( x );
		return findroot( y ) == x;
	}
	
}
	
struct node { int Min, cnt, tag; }t[maxn << 2];
	
node operator + ( node x, node y ) {
	if( x.Min == y.Min ) return { x.Min, x.cnt + y.cnt };
	else if( x.Min < y.Min ) return x;
	else return y;
}
	
#define lson now << 1
#define rson now << 1 | 1
#define inf 0x7f7f7f7f
	
void build( int now, int l, int r ) {
	if( l == r ) { t[now] = { 0, 1, 0 }; return; }
	int mid = ( l + r ) >> 1;
	build( lson, l, mid );
	build( rson, mid + 1, r );
	t[now] = t[lson] + t[rson];
}
	
void pushdown( int now ) {
	t[lson].tag += t[now].tag;
	t[lson].Min += t[now].tag;
	t[rson].tag += t[now].tag;
	t[rson].Min += t[now].tag;
	t[now].tag = 0;
}
	
void modify( int now, int l, int r, int L, int R, int val ) {
	if( r < L or R < l ) return;
	if( L <= l and r <= R ) { t[now].tag += val, t[now].Min += val; return; }
	pushdown( now );
	int mid = ( l + r ) >> 1;
	modify( lson, l, mid, L, R, val );
	modify( rson, mid + 1, r, L, R, val );
	t[now] = t[lson] + t[rson];
	t[now].tag = 0;
}
	
node query( int now, int l, int r, int L, int R ) {
	if( r < L or R < l ) return { inf, 0 };
	if( L <= l and r <= R ) return t[now];
	pushdown( now );
	int mid = ( l + r ) >> 1;
	return query( lson, l, mid, L, R ) + query( rson, mid + 1, r, L, R );
}

int main() {
	scanf( "%d %d", &n, &m );
	for( int i = 1, u, v;i <= m;i ++ ) {
		scanf( "%d %d", &u, &v );
		G[u].push_back( v );
		G[v].push_back( u );
	}
	for( int r = 1, l = 1;r <= n;r ++ ) { //Enumerate position r as the right endpoint 
		//Double pointer l finds the farthest condition satisfying the degree < = 2
		sort( G[r].begin(), G[r].end() );
		for( int i : G[r] ) { //Add the edges belonging to [l,r] connected by each r 
			if( i > r ) break;
			while( i >= l and ( d[i] == 2 or d[r] == 2 ) ) {
				//Before adding this edge, the degree of two points is equal to 2. After adding, the condition of degree < = 2 is certainly not satisfied
				//This indicates that the l left endpoint should be shifted to the right
				//Know that both degrees are < 2 
				for( int j : G[l] )
					if( l < j and ( j < r or ( j == r and l < i ) ) ) d[j] --, d[l] --;
				l ++;
			}
			if( l <= i ) //This side is still added in [l',r] after adjustment
				d[i] ++, d[r] ++; 	 
		}
		f[r] = l;
	}
	build( 1, 1, n );
	long long ans = 0;
	for( int r = 1, l = 1;r <= n;r ++ ) {
		modify( 1, 1, n, 1, r, 1 );
		for( int i : G[r] ) {
			if( i > r ) break;
			while( i >= l and LCT :: connected( i, r ) ) {
				for( int j : G[l] )
					if( l < j and ( j < r or ( j == r and l < i ) ) ) LCT :: cut( j, l );
					/*
					It cannot be written as if (L < J and j < = R). The same is true above
					Because the new edge is i-r
					Maybe i just happens to be l
					If you find that i and r are connected, you must remove the edge of l connection
					l It will access the l-r side, but it has not been added here
					Wrong writing will delete an edge that has not been added at all, resulting in an error 
					*/
				l ++;
			}
			if( l <= i ) LCT :: link( i, r );
			modify( 1, 1, n, 1, i, -1 );
		}
		f[r] = max( f[r], l );
		node MS = query( 1, 1, n, f[r], r );
		if( MS.Min == 1 ) ans += MS.cnt;
	}
	printf( "%lld\n", ans );
	return 0;
}

Tags: data structure Double Pointer LCT

Posted on Tue, 05 Oct 2021 18:37:10 -0400 by ILMV