bzoj 2243 [SDOI2011]染色 树剖+线段树
2015-03-26 20:19
423 查看
题意略。
首先树剖拆出链后建线段树,然后在线段树上维护,线段树节点记录的信息为最左和最右端的颜色(0~1e9,要从-1开始初始化),和该段区间里面的所记录的颜色段数量。因为考虑到,左子树的最右端和右子树的最左端颜色可能相同,那么相同时当前节点记录的颜色段数量便要-1,即( query( lson ) + query( rson ) - ( tr[rt<<1].rc == tr[rt<<1|1].lc) );。而这个过程在查询一条路径递归向上时也要注意,因为当前子链的最左端是前一次操作的最右端,这两端颜色可能会相同(在原树中越靠近根编号越小,画图即可-
-),所以需要记录最左最右端颜色。然后正常的更新就行了。
首先树剖拆出链后建线段树,然后在线段树上维护,线段树节点记录的信息为最左和最右端的颜色(0~1e9,要从-1开始初始化),和该段区间里面的所记录的颜色段数量。因为考虑到,左子树的最右端和右子树的最左端颜色可能相同,那么相同时当前节点记录的颜色段数量便要-1,即( query( lson ) + query( rson ) - ( tr[rt<<1].rc == tr[rt<<1|1].lc) );。而这个过程在查询一条路径递归向上时也要注意,因为当前子链的最左端是前一次操作的最右端,这两端颜色可能会相同(在原树中越靠近根编号越小,画图即可-
-),所以需要记录最左最右端颜色。然后正常的更新就行了。
#include <map> #include <set> #include <queue> #include <stack> #include <vector> #include <cmath> #include <cstdio> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define lson l, mid, rt << 1 #define rson mid + 1, r, rt << 1 | 1 #define pi acos(-1.0) #define eps 1e-8 #define asd puts("asdasdfasdfasdasd"); typedef long long ll; const int inf = 0x3f3f3f3f; const int N = 100010; set <int> s; struct node{ int v, nxt; }e[N << 1]; int tot, cnt, n, m, res; int head ; int pos ; int pre ; int son ; int sz ; int val ; int top ; int dep ; int ww ; void init() { cnt = tot = 0; dep[1] = sz[0] = 0; memset( head, -1, sizeof( head ) ); } void add( int u, int v ) { e[cnt].v = v; e[cnt].nxt = head[u]; head[u] = cnt++; e[cnt].v = u; e[cnt].nxt = head[v]; head[v] = cnt++; } int dfs( int u ) { sz[u] = 1; son[u] = 0; for( int i = head[u]; ~i; i = e[i].nxt ) { int v = e[i].v; if( v == pre[u] ) continue; dep[v] = dep[u] + 1; pre[v] = u; dfs( v ); sz[u] += sz[v]; if( sz[v] > sz[ son[u] ] ) son[u] = v; } } void rebuild( int u, int anc ) { pos[u] = ++tot; top[u] = anc; if( son[u] ) rebuild( son[u], anc ); for ( int i = head[u]; ~i; i = e[i].nxt ) { int v = e[i].v; if( v != pre[u] && v != son[u] ) rebuild( v, v ); } } struct seg{ int l, r; int lc, rc; int x, add; }tr[N << 2]; void pushup( int rt ) { tr[rt].lc = tr[rt<<1].lc; tr[rt].rc = tr[rt<<1|1].rc; tr[rt].x = tr[rt<<1].x + tr[rt<<1|1].x; if( tr[rt<<1].rc == tr[rt<<1|1].lc ) tr[rt].x--; } void down( int rt ) { if( tr[rt].add != -1 ) { tr[rt<<1].add = tr[rt<<1|1].add = tr[rt].add; tr[rt<<1].lc = tr[rt<<1].rc = tr[rt].add; tr[rt<<1|1].lc = tr[rt<<1|1].rc = tr[rt].add; tr[rt<<1].x = tr[rt<<1|1].x = 1; tr[rt].add = -1; } } void build( int l, int r, int rt ) { tr[rt].l = l; tr[rt].r = r; tr[rt].add = -1; if( l == r ) { tr[rt].x = 1; tr[rt].lc = tr[rt].rc = val[l]; return; } int mid = ( tr[rt].l + tr[rt].r ) >> 1; build( lson ); build( rson ); pushup( rt ); } void update( int l, int r, int rt, int col ) { if( l <= tr[rt].l && tr[rt].r <= r ) { tr[rt].x = 1; tr[rt].lc = tr[rt].rc = tr[rt].add = col; return; } down( rt ); int mid = ( tr[rt].l + tr[rt].r ) >> 1; if( r <= mid ) update( l, r, rt << 1, col ); else if( l > mid ) update( l, r, rt << 1 | 1, col ); else { update( lson, col ); update( rson, col ); } pushup( rt ); } void update1( int x, int y, int z ) { while( top[x] != top[y] ) { int f1 = top[x], f2 = top[y]; if( dep[f1] > dep[f2] ) { update( pos[f1], pos[x], 1, z ); x = pre[f1]; } else { update( pos[f2], pos[y], 1, z ); y = pre[f2]; } } if( dep[x] > dep[y] ) swap( x, y ); update( pos[x], pos[y], 1, z ); } //查找新链位置中的最左(最右)端点的颜色,因为任意点的lc = rc,这里返回lc- - int find_col( int pp, int rt ) { if( pp == tr[rt].l && pp == tr[rt].r ) return tr[rt].lc; down( rt ); int mid = ( tr[rt].l + tr[rt].r ) >> 1; if( pp <= mid ) return find_col( pp, rt << 1 ); else return find_col( pp, rt << 1 | 1 ); } int query( int l, int r, int rt ) { if( l <= tr[rt].l && tr[rt].r <= r ) { return tr[rt].x; } down( rt ); int mid = ( tr[rt].l + tr[rt].r ) >> 1; if( r <= mid ) return query( l, r, rt << 1 ); else if( l > mid ) return query( l, r, rt << 1 | 1 ); else return ( query( lson ) + query( rson ) - ( tr[rt<<1].rc == tr[rt<<1|1].lc) ); } int query1( int x, int y ) { int res = 0; int lc = -1, rc = -1; while( top[x] != top[y] ) { int f1 = top[x], f2 = top[y]; if( dep[f1] > dep[f2] ) { res += query( pos[f1], pos[x], 1 ); if( find_col( pos[x], 1 ) == lc ) --res; lc = find_col( pos[f1], 1 ); x = pre[f1]; } else { res += query( pos[f2], pos[y], 1 ); if( find_col( pos[y], 1 ) == rc ) --res; rc = find_col( pos[f2], 1 ); y = pre[f2]; } } if( dep[x] < dep[y] ) res += query( pos[x], pos[y], 1 ); else res += query( pos[y], pos[x], 1 ); if( find_col( pos[x], 1 ) == lc ) --res; if( find_col( pos[y], 1 ) == rc ) --res; return res; } int main() { while(~scanf("%d%d", &n, &m)) { init(); int u, v, w; for( int i = 1; i <= n; ++i ) scanf("%d", &ww[i]); for( int i = 1; i < n; ++i ) { scanf("%d%d", &u, &v); add( u, v ); } dfs( 1 ); rebuild( 1, 1 ); for( int i = 1; i <= n; ++i ) { val[ pos[i] ] = ww[i]; } build( 1, n, 1 ); char op[10]; while( m-- ) { scanf("%s", op); if( op[0] == 'C' ) { scanf("%d%d%d", &u, &v, &w); update1( u, v, w ); } else { scanf("%d%d", &u, &v); int ans = query1( u, v ); printf("%d\n", ans); } } } }
相关文章推荐
- bzoj 2243: [SDOI2011]染色 线段树区间合并+树链剖分
- bzoj2243 [SDOI2011]染色(树链剖分,线段树求颜色段数)
- BZOJ 2243: [SDOI2011]染色 树链剖分+线段树区间合并
- 【BZOJ2243】[SDOI2011]染色 树链剖分+线段树
- BZOJ 2243: [SDOI2011]染色 树链剖分 倍增lca 线段树
- 【BZOJ2243】[SDOI2011]染色【树链剖分】【线段树】
- BZOJ 2243 [SDOI2011]染色 (树链剖分)(线段树区间修改)
- 树链剖分+线段树【SDOI2011】 bzoj2243 染色
- BZOJ 2243 [SDOI2011]染色 树链剖分+LCA+区间合并线段树
- 【bzoj2243】 [SDOI2011]染色 树链剖分+线段树
- bzoj 2243 [SDOI2011]染色(树链剖分,线段树)
- BZOJ 2243: [SDOI2011]染色 (树链剖分,点权,线段树)
- [BZOJ2243][[SDOI2011]染色][树链剖分+线段树]
- [BZOJ2243][SDOI2011]染色(树剖+线段树)
- BZOJ 2243: [SDOI2011]染色 (树链剖分+线段树合并)
- bzoj 2243 [SDOI2011]染色 (线段树 + 树链剖分)
- [SDOI2011][BZOJ2243] 染色|线段树|树链剖分
- BZOJ-2243: [SDOI2011]染色 (树链剖分 入门题 线段树 区间修改查询 维护端点值)
- 【BZOJ】2243 [SDOI2011]染色 树链剖分
- BZOJ 2243: [SDOI2011]染色 树链剖分