bzoj 2243 [SDOI2011]染色 树剖+线段树

来源:互联网 发布:淘宝固定背景尺寸 编辑:程序博客网 时间:2024/06/01 01:34

题意略。

首先树剖拆出链后建线段树,然后在线段树上维护,线段树节点记录的信息为最左和最右端的颜色(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[N];int pos[N];int pre[N];int son[N];int sz[N];int val[N];int top[N];int dep[N];int ww[N];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 );elsereturn 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 );elsereturn ( 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 );elseres += 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);}}}}


0 0
原创粉丝点击