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