[SPOJ COT2]-Count on a tree II-树上莫队
2018-01-10 10:22
429 查看
说在前面
乘着这几天大力填补之前留下的坑…树上分块果然还是使用 王室联邦法 最好了=w=
题目
SPOJ COT2传送门题目大意
给定一棵有N个节点的树,树上的节点都有各自的权值现在给出M个询问,询问u到v的路径上有多少种不同的权值
输入输出格式
输入格式:第一行两个整数N,M
接下来N-1行,每行两个整数表示树边连接的点
再接下来M行,每行两个数u,v表示询问
输出格式:
对于每个询问,输出一行一个整数表示答案
解法
(像这种树剖和LCT没法维护的,果然还是用莫队好了=w=)树分块呢,大概有这样的一些方法:
王室联邦分块法:可以保证每个块的大小和直径都不超过2N−−√−1,但是不保证块联通
DFS序分块法:首先是好写(毕竟转化成了序列问题),严格保证块大小N−−√,但是不保证直径,也不保证联通。处理子树信息比较方便
size分块:检查当前节点的父亲所在块的大小,如果小于N−−√就把当前节点加入进去,不然新开块。块大小最坏N−−√,保证块内联通,还保证直径,多么优美啊=w=,可惜不能保证块个数(一个菊花图就死了恍恍惚惚哈哈哈哈)….
于是这道题呢,采用王室联邦分块法
维护的是两个端点到根的路径上的 贡献的异或。于是假设当前点为nowu,nowv,那么当前就应该维护下了nowu到nowv路径上的答案(不包含LCA,因为LCA会被异或两遍)。在查答案的时候单独加上LCA的贡献就可以了
关于修改,假设下一个询问的点为aimu,aimv,那么就把nowu挪动到aimu去,nowv挪动到aimv去,这一步可以通过暴力跳它们的父亲来实现(因为每个块大小直径都有保证,所以总的复杂度也是可以保证的)。
下面是自带大常数的代码
#include <cmath> #include <cstdio> #include <cstring> #include <algorithm> using namespace std ; int N , M , tp , head[40005] ; int dfn[40005] , dfs_c , val[40005] ; int uninum , bel[40005] , Bsiz , Btot , ans[100005] ; struct Unique_Data{ int num , id ; bool operator < ( const Unique_Data &A ) const { return num < A.num ; } }Uni[40005] ; struct Queries{ int u , v , id ; bool operator < ( const Queries &A ) const { return ( bel[u] < bel[A.u] ) || ( bel[u] == bel[A.u] && dfn[v] < dfn[A.v] ) ; } }Q[100005] ; struct Path{ int pre , to ; }p[80005] ; void In( int t1 , int t2 ){ p[++tp].pre = head[t1] ; p[ head[t1] = tp ].to = t2 ; } void Unique_(){ sort( Uni + 1 , Uni + N + 1 ) ; for( int i = 1 , las = -2e9 ; i <= N ; i ++ ){ if( las != Uni[i].num ){ uninum ++ ; las = Uni[i].num ; } val[ Uni[i].id ] = uninum ; } } int dep[40005] , fa[16][40005] , sta[40005] , topp ; void dfs( int u ){ dfn[u] = ++dfs_c ; int last = topp ; for( int i = head[u] ; i ; i = p[i].pre ){ int v = p[i].to ; if( v == fa[0][u] ) continue ; dep[v] = dep[u] + 1 ; fa[0][v] = u ; dfs( v ) ; if( topp - last >= Bsiz ){ Btot ++ ; while( topp != last ) bel[ sta[topp--] ] = Btot ; } } sta[++topp] = u ; } void getST(){ for( int i = 1 ; i <= 15 ; i ++ ) for( int j = 1 ; j <= N ; j ++ ) fa[i][j] = fa[i-1][ fa[i-1][j] ] ; } int Lca( int u , int v ){ if( dep[u] < dep[v] ) swap( u , v ) ; int t = dep[u] - dep[v] , x = 0 ; while( t ){ if( t&1 ) u = fa[x][u] ; t >>= 1 ; x ++ ; } if( u == v ) return u ; for( int i = 15 ; i >= 0 ; i -- ) if( fa[i][u] != fa[i][v] ) u = fa[i][u] , v = fa[i][v] ; return fa[0][u] ; } void init(){ Unique_() ; Bsiz = sqrt( N ) ; dfs( 1 ) ; fa[0][1] = 1 ; if( topp ){ Btot ++ ; while( topp ) bel[ sta[topp--] ] = Btot ; } sort( Q + 1 , Q + M + 1 ) ; getST() ; } bool vis[40005] ; int cnt[40005] , nowans ; void Xor( int x ){ if( vis[x] ){ vis[x] = false ; if( -- cnt[ val[x] ] == 0 ) nowans -- ; } else { vis[x] = true ; if( ++ cnt[ val[x] ] == 1 ) nowans ++ ; } } void Move_( int u , int v ){ if( dep[u] < dep[v] ) swap( u , v ) ; while( dep[u] > dep[v] ){ Xor( u ) ; u = fa[0][u] ; } while( u != v ){ Xor( u ) ; Xor( v ) ; u = fa[0][u] , v = fa[0][v] ; } } void solve(){ int nowu = 1 , nowv = 1 ; for( register int i = 1 ; i <= M ; i ++ ){ int aimu = Q[i].u , aimv = Q[i].v , LCA = Lca( aimu , aimv ) ; Move_( nowu , aimu ) ; nowu = aimu ; Move_( nowv , aimv ) ; nowv = aimv ; Xor( LCA ) ; ans[ Q[i].id ] = nowans ; Xor( LCA ) ; } for( register int i = 1 ; i <= M ; i ++ ) printf( "%d\n" , ans[i] ) ; } inline void read_( int &x ){ int flag = 1 ; x = 0 ; char ch = getchar() ; while( ch < '0' || ch > '9' ){ if( ch == '-' ) flag = -1 ; ch = getchar() ; } while( ch >='0' && ch <='9' ) x = ( x << 1 ) + ( x << 3 ) + ch - '0' , ch = getchar() ; x *= flag ; } int main(){ scanf( "%d%d" , &N , &M ) ; for( register int i = 1 ; i <= N ; i ++ ){ read_( val[i] ) ; Uni[i].num = val[i] , Uni[i].id = i ; } for( int i = 1 , u = 0 , v = 0 ; i < N ; i ++ ){ read_( u ) , read_( v ) ; In( u , v ) ; In( v , u ) ; } for( register int i = 1 ; i <= M ; i ++ ){ read_( Q[i].u ) , read_( Q[i].v ) ; Q[i].id = i ; } init() ; solve() ; }
相关文章推荐
- spoj_cot2 Count on a tree II(树上莫队+离散化)
- SPOJ COT2 Count on a tree II(路径树上莫队)
- 【SPOJ COT2】Count on a tree II,树上莫队
- SPOJ-COT2 Count on a tree II(树上莫队)
- [spoj COT2- Count on a tree II] 树上莫队
- spoj_cot2 Count on a tree II(树上莫队+离散化)
- SPOJ COT2 Count on a tree II 树上莫队
- [树上莫队] SPOJ COT2 Count on a tree II
- SPOJ - COT2 : Count on a tree II (树上莫队)
- SPOJ10707 COT2 - Count on a tree II 【树上莫队】
- SPOJ Count on a tree II(树上莫队)
- SPOJ--Count on a tree II(树上莫队)
- 【SPOJ10707】Count on a tree II-树上莫队算法
- 【SPOJ】Count On A Tree II(树上莫队)
- SPOJ 10707 Count on a Tree II 树上莫队
- SPOJ:COT2 Count on a tree II
- 【spoj】【COT2 - Count on a tree II】【莫队算法】
- SPOJ.COT2 Count on a tree II(树上莫队)
- BZOJ 2589 Spoj 10707 Count on a tree II 强制在线莫队算法(TLE)
- SPOJ COT2 Count on a tree II [树上莫队]