其他分享
首页 > 其他分享> > 2022.1 写题记录

2022.1 写题记录

作者:互联网

P2709 小B的询问

莫队的板子题。

维护一个 \(c_i\) 为 \(i\) 的出现次数,如果 \(c_i \gets c_i\pm1\) 的话,\(c_i^2\) 的值完全平方公式展开一下就可得减去 \(2c_i+1\) 或加上 \(2c_i-1\)。

然后莫队维护一下就好了,时间复杂度\(O(n^{1.5})\)。

点击查看代码
# include <cstdio>
# include <iostream>
# include <algorithm>
# include <cmath>

typedef long long ll;

namespace IO{
	inline int read(){
		int ret = 0 , ti = 1;
		char u = getchar();
		while( ! isdigit( u ) ){ if( u == '-' ) ti = -1; u = getchar(); }
		while( isdigit( u ) ) ret = ret * 10 + u - '0' , u = getchar();
		return ret * ti;
	}	
}

using namespace std;

const int N = 5e4 + 225;

int n , m , w;
int siz;
int cnt[ N ] , a[ N ];
ll ans[ N ];
ll sum;

struct Query{
	int l , r , id , pos;
}q[ N ];

inline bool comp( Query u , Query v ){
	return u . pos == v . pos ? u . r < v . r : u . pos < v . pos;
}

inline void del( int u ){
	-- cnt[ a[ u ] ];
	sum -= 2 * cnt[ a[ u ] ] + 1;
}

inline void add( int u ){
	++ cnt[ a[ u ] ];
	sum += 2 * cnt[ a[ u ] ] - 1;
}

void solve(){
	int l = 1 , r = 0;
	sort( q + 1 , q + m + 1 , comp );
	for( int i = 1 ; i <= m ; i ++ ){
		while( l < q[ i ] . l ) del( l ++ );
		while( l > q[ i ] . l ) add( -- l );
		while( r < q[ i ] . r ) add( ++ r );
		while( r > q[ i ] . r ) del( r -- );
		ans[ q[ i ] . id ] = sum;
	}
	for( int i = 1 ; i <= m ; i ++ ) printf( "%lld\n" , ans[ i ] );
}

void input(){
	n = IO :: read() , m = IO :: read() , w = IO :: read();
	siz = sqrt( n ) * 0.9;
	for( int i = 1 ; i <= n ; i ++ ) a[ i ] = IO :: read();
	for( int i = 1 ; i <= m ; i ++ )
		q[ i ] . l = IO :: read() , q[ i ] . r = IO :: read() , q[ i ] . id = i , q[ i ] . pos = ( q[ i ] . l - 1 ) / siz + 1;
}

int main(){
	input();
	solve();
	return 0;
}

P7764 [COCI2016-2017#5] Poklon

还是莫队。

当一次指针移动对答案有贡献的时候,就是移动前该值为 \(2\) 或移动后该值为 \(2\),按情况加减就好。

哦这个还要离散化的。

时间复杂度 \(O(n^{1.5})\)。

点击查看代码
# include <cstdio>
# include <iostream>
# include <algorithm>
# include <cmath>
# include <vector>

namespace IO{
	inline int read(){
		int ret = 0 , ti = 1;
		char u = getchar();
		while( ! isdigit( u ) ){ if( u == '-' ) ti = -1; u = getchar(); }
		while( isdigit( u ) ) ret = ret * 10 + u - '0' , u = getchar();
		return ret * ti;
	}	
}

using namespace std;

const int N = 5e5 + 225;

int n , m , w;
int siz;
int cnt[ N ] , a[ N ];
int ans[ N ];
int sum;
vector< int > re;

struct Query{
	int l , r , id , pos;
}q[ N ];

inline bool comp( Query u , Query v ){
	return u . pos == v . pos ? u . r < v . r : u . pos < v . pos;
}

inline void del( int u ){
	if( cnt[ a[ u ] ] == 2 ) -- sum;
	-- cnt[ a[ u ] ];
	if( cnt[ a[ u ] ] == 2 ) ++ sum;
}

inline void add( int u ){
	if( cnt[ a[ u ] ] == 2 ) -- sum;
	++ cnt[ a[ u ] ];
	if( cnt[ a[ u ] ] == 2 ) ++ sum;
}

void solve(){
	sort( re . begin() , re . end() );
	re . erase( unique( re . begin() , re . end() ) , re . end() );
	for( int i = 1 ; i <= n ; i ++ ) a[ i ] = lower_bound( re . begin() , re . end() , a[ i ] ) - re . begin();
	int l = 1 , r = 0;
	sort( q + 1 , q + m + 1 , comp );
	for( int i = 1 ; i <= m ; i ++ ){
		while( l < q[ i ] . l ) del( l ++ );
		while( l > q[ i ] . l ) add( -- l );
		while( r < q[ i ] . r ) add( ++ r );
		while( r > q[ i ] . r ) del( r -- );
		ans[ q[ i ] . id ] = sum;
	}
	for( int i = 1 ; i <= m ; i ++ ) printf( "%d\n" , ans[ i ] );
}

void input(){
	n = IO :: read() , m = IO :: read();
	siz = sqrt( n ) * 0.9;
	re . push_back( -1 );
	for( int i = 1 ; i <= n ; i ++ ) a[ i ] = IO :: read() , re . push_back( a[ i ] );
	for( int i = 1 ; i <= m ; i ++ )
		q[ i ] . l = IO :: read() , q[ i ] . r = IO :: read() , q[ i ] . id = i , q[ i ] . pos = ( q[ i ] . l - 1 ) / siz + 1;
}

int main(){
	input();
	solve();
	return 0;
}

P3398 仓鼠找sugar

这题是需要判断树上两条路径是否相交。

记两条路径分别为 \(p_1(u,v)\),\(p_2(x,y)\),它们各自的 \(LCA\) 为 \(f_{p_1},f_{p_2}\)。

那么必定会有 \(f_{p_1}\) 在 \(p_2\) 上或 \(f_{p_2}\) 在 \(p_1\) 上。

其实我也不会证这个东西的正确性...不过这个是对的。

那么判某个点是否在一条路径上的话,这样想,如果这个点到路径两端点的距离和这个路径的长度相等的话,这个点就在这个路径上了。

然后距离就用深度差分一下,树剖一个 \(LCA\) 就水过了。

\(O(n\log n)\)。

其实一开始想的是用树剖链改链查的方式打标记,先将 \(p_1\) 打上标记,再查询 \(p_2\) 是否有标记即可。

这样子是 \(O(n\log^2 n)\)。

点击查看代码
# include <iostream>
# include <cstdio>
# include <cmath>

namespace IO{
	inline int read(){
		int ret = 0 , ti = 1;
		char u = getchar();
		while( ! isdigit( u ) ){ if( u == '-' ) ti = -1; u = getchar(); }
		while( isdigit( u ) ) ret = ret * 10 + u - '0' , u = getchar();
		return ret * ti;
	}
}

const int N = 6e5 + 225;

using namespace std;

// -- Graph -- 

# define E( u ) head[ u ]
# define u( u ) edge[ u ] . frm
# define v( u ) edge[ u ] . to
# define nxt( u ) edge[ u ] . nxt
# define forE( u , i ) for( int i = head[ u ] ; i ; i = edge[ i ] . nxt )

struct Edge{		
	int nxt , to;
}edge[ N << 1 ];
	
int head[ N ] , eg;
	
inline void add_edge( int u , int v ){
	edge[ ++ eg ] = { head[ u ] , v } , head[ u ] = eg;
}

// -- Graph -- 

int n , q , cnt , rt;
int idx[ N ] , dep[ N ] , siz[ N ] , ch[ N ] , fa[ N ] , tp[ N ]; 

void dfs1( int u , int fath ){
	fa[ u ] = fath , dep[ u ] = dep[ fath ] + 1 , siz[ u ] = 1;
	forE( u , i ){
		int v = v( i );
		if( v == fath ) continue;
		dfs1( v , u );
		siz[ u ] += siz[ v ];
		if( siz[ ch[ u ] ] < siz[ v ] ) ch[ u ] = v;
	}
}

void dfs2( int u , int top ){
	idx[ u ] = ++ cnt;
	tp[ u ] = top;
	if( ch[ u ] ) dfs2( ch[ u ] , top );
	forE( u , i ){
		int v = v( i );
		if( v == fa[ u ] || v == ch[ u ] ) continue;
		dfs2( v , v );
	}
}

int lca( int u , int v ){
	while( tp[ u ] != tp[ v ] ){
		if( dep[ tp[ u ] ] < dep[ tp[ v ] ] ) swap( u , v );
		u = fa[ tp[ u ] ];
	}
	return dep[ u ] < dep[ v ] ? u : v;	
}

int dis( int u , int v ){
	int f = lca( u , v );
	return abs( dep[ f ] - dep[ u ] ) + abs( dep[ f ] - dep[ v ] );
}

void solve(){
	for( int i = 1 ; i <= q ; i ++ ){
		int u = IO :: read() , v = IO :: read();
		int p = IO :: read() , q = IO :: read();
		
		int f1 = lca( u , v ) , f2 = lca( p , q );
		
		/*int disuv = dis( u , v );
		int dispq = dis( p , q );
		
		int fuv = lca( u , v ) , fpq = lca( p , q );
		int disfpquv = dis( fpq , u ) + dis( fpq , v );
		int disfuvpq = dis( fuv , p ) + dis( fuv , q );*/
		if( dis( u , v ) == dis( u , f2 ) + dis( v , f2 ) || dis( p , q ) == dis( p , f1 ) + dis( q , f1 ) ) printf( "Y\n" );
		else printf( "N\n" );
	}
}

void input(){
	n = IO :: read() , q = IO :: read();
	for( int i = 1 ; i <= n - 1 ; i ++ ){
		int u = IO :: read() , v = IO :: read();
		add_edge( u , v );
		add_edge( v , u );
	}	
}

int main(){
	input();
	dfs1( 1 , 0 );
	dfs2( 1 , 1 );
	solve();
	return 0;
}

标签:cnt,记录,int,sum,ret,写题,--,include,2022.1
来源: https://www.cnblogs.com/yukari1735/p/15807763.html