【HDU】5267 pog loves szh IV【动态点分治】

传送门:【HDU】5267 pog loves szh IV

题目分析:首先我们用树分治,对每一个分治重心,以此为根的子树,建立一棵线段树。可以发现总节点数只有$O(NlogN)$,因为每一层都是$N$个节点,且只有$logN$层。然后,还有一个特点就是,一个点最多属于$logN$个中心,这样我们查询和更新,就是在$logN$重心树中用$logN$的复杂度更新线段树的区间。线段树的每个叶节点表示这个节点到该重心树的树根的异或值。然后接下来就不难了,仔细想想基本都可以理论AC了……当然做起来可能不是那么轻松……对于这个题目分析我就说道这好了。

PS:这是我写过最长的代码,加上调试信息,都快要10000B了……OWO


13935644 2015-06-29 17:56:10 Accepted 5267 2480MS 13940K 9648 B G++ poursoul


my code:

#include <bits/stdc++.h>
using namespace std ;

typedef long long LL ;

#define clr( a , x ) memset ( a , x , sizeof a )
#define cpy( a , x ) memcpy ( a , x , sizeof a )
#define ls T[o].Ls
#define rs T[o].Rs
#define lson rs , T[o].l , m
#define rson ls , m + 1 , T[o].r
#define mid ( ( T[o].l + T[o].r ) >> 1 )

const int MAXN = 10005 ;
const int MAXE = 20005 ;

struct Edge {
	int v , n ;
	Edge () {}
	Edge ( int v , int n ) : v ( v ) , n ( n ) {}
} ;

struct Node {
	int L , R , tree , subtree ;
	Node () {}
	Node ( int L , int R , int t , int t2 = 0 ) : L ( L ) , R ( R ) , tree ( t ) , subtree ( t2 ) {}
} ;
struct Tree {
	int l , r , Ls , Rs , sum , lazy ;
} ;

Edge E[MAXE] ;
int H[MAXN] , cntE ;
int vis[MAXN] , siz[MAXN] , pre[MAXN] ;
int Q[MAXN] , head , tail ;
int in[MAXN * 15] , ou[MAXN * 15] , dfs_clock ;
pair < int , int > op[MAXN] ;
//pair < pair < int , int > , int > Root[MAXN * 2] ;
vector < Node > G[MAXN] ;
Node node[MAXN] , Root[MAXN * 2] ;
int cnt ;

int n , m ;
int val[MAXN] ;
LL ans[MAXN] , res ;
int zero[MAXN * 2] , one[MAXN * 2] ;
Tree T[MAXN * 60] ;
int Troot[MAXN * 2] , cur ;
int tot[MAXN * 2] , tmp[MAXN * 2] ;

void init () {
	cnt = 0 ;
	cntE = 0 ;
	dfs_clock = 0 ;
	clr ( tot , 0 ) ;
	clr ( vis , 0 ) ;
	clr ( ans , 0 ) ;
	clr ( H , -1 ) ;
}

void addedge ( int u , int v ) {
	E[cntE] = Edge ( v , H[u] ) ;
	H[u] = cntE ++ ;
}

int get_root ( int s ) {
	head = tail = 0 ;
	pre[s] = 0 ;
	Q[tail ++] = s ;
	while ( head != tail ) {
		int u = Q[head ++] ;
		for ( int i = H[u] ; ~i ; i = E[i].n ) {
			int v = E[i].v ;
			if ( vis[v] || v == pre[u] ) continue ;
			pre[v] = u ;
			Q[tail ++] = v ;
		}
	}
	int root = s , root_siz = n ;
	while ( head ) {
		int u = Q[-- head] , cnt = 0 ;
		siz[u] = 1 ;
		for ( int i = H[u] ; ~i ; i = E[i].n ) {
			int v = E[i].v ;
			if ( vis[v] || v == pre[u] ) continue ;
			siz[u] += siz[v] ;
			if ( cnt < siz[v] ) cnt = siz[v] ;
		}
		cnt = max ( cnt , tail - siz[u] ) ;
		if ( cnt < root_siz ) {
			root_siz = cnt ;
			root = u ;
		}
	}
	return root ;
}

void get_tree ( int u , int f , int tree , int subtree ) {
	in[u] = ++ dfs_clock ;
	for ( int i = H[u] ; ~i ; i = E[i].n ) {
		int v = E[i].v ;
		if ( vis[v] || v == f ) continue ;
		get_tree ( v , u , tree , subtree ) ;
	}
	ou[u] = dfs_clock ;
	G[u].push_back ( Node ( in[u] , ou[u] , tree , subtree ) ) ;
}

void dfs ( int u ) {
	int root = get_root ( u ) ;
	vis[root] = 1 ;
	int tree = ++ cnt ;
	in[root] = ++ dfs_clock ;
	for ( int i = H[root] ; ~i ; i = E[i].n ) {
		int v = E[i].v ;
		if ( vis[v] ) continue ;
		int subtree = ++ cnt ;
		get_tree ( v , 0 , tree , subtree ) ;
		//Root[subtree] = make_pair ( make_pair ( in[v] , ou[v] ) , tree ) ;
		Root[subtree] = Node ( in[v] , ou[v] , tree ) ;
		tot[tree] -= ( ou[v] - in[v] ) * ( ou[v] - in[v] + 1 ) ;
	}
	ou[root] = dfs_clock ;
	tot[tree] += ( ou[root] - in[root] ) * ( ou[root] - in[root] + 1 ) ;
	//Root[tree] = make_pair ( make_pair ( in[root] , ou[root] ) , 0 ) ;
	Root[tree] = Node ( in[root] , ou[root] , tree ) ;
	node[root] = Node ( in[root] , ou[root] , tree ) ;
	for ( int i = H[root] ; ~i ; i = E[i].n ) {
		int v = E[i].v ;
		if ( !vis[v] ) dfs ( v ) ;
	}
}

void pushdown ( int o ) {
	int m = mid ;
	if ( T[o].lazy ) {
		T[ls].lazy ^= 1 ;
		T[rs].lazy ^= 1 ;
		T[ls].sum = m - T[o].l + 1 - T[ls].sum ;
		T[rs].sum = T[o].r - m - T[rs].sum ;
		T[o].lazy = 0 ;
	}
}

void build ( int& o , int l , int r ) {
	o = ++ cur ;
	T[o].l = l ;
	T[o].r = r ;
	T[o].sum = T[o].lazy = 0 ;
	if ( l == r ) return ;
	int m = mid ;
	build ( T[o].Ls , l , m ) ;
	build ( T[o].Rs , m + 1 , r ) ;
}

void update ( int L , int R , int o ) {
	if ( L <= T[o].l && T[o].r <= R ) {
		T[o].lazy ^= 1 ;
		T[o].sum = T[o].r - T[o].l + 1 - T[o].sum ;
		return ;
	}
	pushdown ( o ) ;
	int m = mid ;
	if ( L <= m ) update ( L , R , ls ) ;
	if ( m <  R ) update ( L , R , rs ) ;
	T[o].sum = T[ls].sum + T[rs].sum ;
}

int query ( int L , int R , int o ) {
	if ( L <= T[o].l && T[o].r <= R ) return T[o].sum ;
	pushdown ( o ) ;
	int m = mid ;
	if ( R <= m ) return query ( L , R , ls ) ;
	if ( m <  L ) return query ( L , R , rs ) ;
	return query ( L , R , ls ) + query ( L , R , rs ) ;
}


void show ( int o ) {
	if ( T[o].l == T[o].r ) {
		if ( T[o].l <= 5 ) printf ( "%d " , T[o].sum ) ;
		if ( T[o].l == 5 ) printf ( "\n" ) ;
		return ;
	}
	pushdown ( o ) ;
	int m = mid ;
	show ( ls ) ;
	show ( rs ) ;
}

void solve () {
	int u , v ;
	init () ;
	for ( int i = 1 ; i <= n ; ++ i ) {
		scanf ( "%d" , &val[i] ) ;
		G[i].clear () ;
	}
	for ( int i = 1 ; i < n ; ++ i ) {
		scanf ( "%d%d" , &u , &v ) ;
		addedge ( u , v ) ;
		addedge ( v , u ) ;
	}
	dfs ( 1 ) ;
	for ( int i = 1 ; i <= m ; ++ i ) {
		scanf ( "%d%d" , &op[i].first , &op[i].second ) ;
	}
	
	/*for ( int j = 1 ; j <= n ; ++ j ) {
		printf ( "%d %d\n" , node[j].first , node[j].second ) ;
	}*/
	for ( int i = 0 ; i < 15 ; ++ i ) {
		cur = 0 ;
		clr ( tmp , 0 ) ;
		for ( int j = 1 ; j <= n ; ++ j ) {
			build ( Troot[node[j].tree] , node[j].L , node[j].R ) ;
		}
		for ( int j = 1 ; j <= n ; ++ j ) if ( val[j] & 1 ) {
			//printf ( "%d %d\n" , node[j].first , node[j].second , dfs_clock ) ;
			update ( node[j].L , node[j].R , Troot[node[j].tree] ) ;
			for ( int k = 0 ; k < G[j].size () ; ++ k ) {
				int L = G[j][k].L ;
				int R = G[j][k].R ;
				int tree = G[j][k].tree ;
				//if ( i == 0 ) printf ( "%d %d %d %d\n" , L , R , T[Troot[tree]].l , T[Troot[tree]].r ) ;
				update ( L , R , Troot[tree] ) ;
			}
		}
		res = 0 ;
		for ( int j = 1 ; j <= cnt ; ++ j ) {
			int tree = Root[j].tree ;
			int L = Root[j].L ;
			int R = Root[j].R ;
			int L1 = Root[tree].L ;
			int R1 = Root[tree].R ;
			//if ( !i ) printf ( "%d %d %d %d %d %d\n" , L , R , L1 , R1 , j , tree ) ;
			one[j] = query ( L , R , Troot[tree] ) ;
			//printf ( "ok\n" ) ;
			zero[j] = R - L + 1 - one[j] ;
			//if ( i == 0 ) printf ( "%d %d %d %d\n" , L , R , zero[j] , one[j] ) ;
		}
		for ( int j = 1 ; j <= cnt ; ++ j ) {
			if ( Root[j].tree != j ) {
				int tree = Root[j].tree ;
				int L = Root[tree].L ;
				int color = query ( L , L , Troot[tree] ) ;
				int x1 = zero[tree] - zero[j] ;
				int y1 = one[tree] - one[j] ;
				int x2 = zero[j] ;
				int y2 = one[j] ;
				//if ( i == 0 ) printf ( "%d %d %d %d\n" , x1 , x2 , y1 , y2 ) ;
				//if ( !i ) printf ( "%d %d %d %d\n" , x1 , x2 , y1 , y2 ) ;
				//if ( !i ) printf ( "1.%lld " , res ) ;
				int t ;
				if ( color ) t = x1 * x2 + y1 * y2 ;
				else t = x1 * y2 + x2 * y1 ;
				tmp[tree] += t ;
				res += t ;
				//if ( !i ) printf ( "%lld\n" , res ) ;
			} else {
				int tree = Root[j].tree ;
				int L = Root[tree].L ;
				int color = query ( L , L , Troot[tree] ) ;
				//if ( !i ) printf ( "0.%lld " , res ) ;
				res += one[j] - color ;
				tmp[tree] += one[j] - color ;
				//if ( !i ) printf ( "%lld\n" , res ) ;
			}
		}
		//if ( i < 3 ) printf ( "%lld\n" , res ) ;
		ans[0] += res * ( 1 << i ) ;
		for ( int j = 1 ; j <= m ; ++ j ) {
			int x = op[j].first ;
			if ( ( val[x] & 1 ) != ( op[j].second & 1 ) ) {
				for ( int k = 0 ; k < G[x].size () ; ++ k ) {
					int L = G[x][k].L ;
					int R = G[x][k].R ;
					int tree = G[x][k].tree ;
					int subtree = G[x][k].subtree ;
					int color = query ( Root[tree].L , Root[tree].L , Troot[tree] ) ;
					int t ;
					if ( i == 0 && j == 4 ) {
						//printf ( "mid:%d %d %d %d\n" , color , op[j].second & 1 , tree , subtree ) ;
					}
					one[subtree] = query ( Root[subtree].L , Root[subtree].R , Troot[tree] ) ;
					zero[subtree] = Root[subtree].R - Root[subtree].L + 1 - one[subtree] ;
					if ( i == 0 && j == 4 ) {
						//printf ( "next:%lld %d %d %d %d %d %d\n" , res , tmp[tree] , zero[subtree] , one[subtree] , zero[tree] , one[tree] , t ) ;
					}
					zero[tree] -= zero[subtree] ;
					one[tree] -= one[subtree] ;
					if ( color ) t = zero[tree] * zero[subtree] + one[tree] * one[subtree] ;
					else t = zero[tree] * one[subtree] + zero[subtree] * one[tree] ;
					res -= 2 * t ;
					tmp[tree] -= 2 * t ;
					if ( i == 0 && j == 4 ) {
						//printf ( "next:%lld %d %d %d %d %d %d\n" , res , tmp[tree] , zero[subtree] , one[subtree] , zero[tree] , one[tree] , t ) ;
					}
					update ( L , R , Troot[tree] ) ;
					one[subtree] = query ( Root[subtree].L , Root[subtree].R , Troot[tree] ) ;
					zero[subtree] = Root[subtree].R - Root[subtree].L + 1 - one[subtree] ;
					if ( color ) t = zero[tree] * zero[subtree] + one[tree] * one[subtree] ;
					else t = zero[tree] * one[subtree] + zero[subtree] * one[tree] ;
					res += 2 * t ;
					tmp[tree] += 2 * t ;
					zero[tree] += zero[subtree] ;
					one[tree] += one[subtree] ;
				}
				int L = node[x].L ;
				int R = node[x].R ;
				int tree = node[x].tree ;
				int color = query ( L , L , Troot[tree] ) ;
				//if ( i == 0 && j == 1 ) printf ( "%d %d %lld\n" , color , op[j].second & 1 , res ) ;
				swap ( zero[tree] , one[tree] ) ;
				update ( L , R , Troot[tree] ) ;
				res -= tmp[tree] ;
				tmp[tree] = tot[tree] - tmp[tree] ;
				res += tmp[tree] ;
				val[x] ^= 1 ;
			}
			ans[j] += res * ( 1 << i ) ;
		}
		for ( int j = 1 ; j <= n ; ++ j ) {
			val[j] >>= 1 ;
		}
		for ( int j = 1 ; j <= m ; ++ j ) {
			op[j].second >>= 1 ;
		}
	}
	for ( int i = 1 ; i <= m ; ++ i ) {
		printf ( "%I64d\n" , ans[i] ) ;
	}
}

int main () {
	while ( ~scanf ( "%d%d" , &n , &m ) ) solve () ;
	return 0 ;
}


你可能感兴趣的:(树分治)