[HDU6793] Tokitsukaze and Colorful Tree
题目
又是一个条历新年,窗前的灼之花又盛开了。
时隔多年,现在只有这一棵树上盛开着残存的 \(n\) 朵灼之花了。
尽管如此,这些灼之 花仍散发出不同色彩的微弱的光芒。 灼之花的生命极为短暂,但它的花色与光亮瞬息万变。
作为条条的粉丝,Little Q 细致 地记录了最初每朵灼之花的花色 \(c_i\) 和光亮 \(l_i\) ,以及接下来的 \(m\) 秒中灼之花的变化,第 \(i\) 秒会发生下面两种变化之一:
- " \(1\ t_i\ c_i'\) " 第 \(t_i\) 朵灼之花的颜色变为 \(c_i'\) ;
- " \(2\ t_i\ l_i'\) " 第 \(t_i\) 朵灼之花的光亮变为 \(l_i'\) ;
灼之花一齐盛开的景象令人过目难忘,其美丽值为每对生长在不同枝杈的相同颜色的灼之花的光亮值的异或和:
\]
数据范围: \(1\le c_i,c_i'\le n,m\le 10^6, 0\le l_i,l_i'\le 2^{20}\) 。
原题:[HDU6793]Tokitsukaze and Colorful Tree 。
分析
首先需要一些基础的分析。
第一步,异或首先按位进行拆分。
第二步,显然,我们总可以将变化拆分成向某个颜色的集合中插入或者删除一个点。
第三步,接着我们需要考虑动态地维护插入一个点或删除一个点之后,同种颜色中异或为 1 的符合条件的点对数量。
我们只需要考虑与变化的点有关的点对。异或为 1 可以简单地分类讨论,我们需要考虑 \(\operatorname{LCA}\) 的限制。
不难发现,我们只需要减去下列不合法的点即可:
对应点在根到当前点的路径上。
对应点在当前点的子树内。
第一个部分可以考虑维护贡献,等价于每次修改子树,也就是 DFS 序上的一段区间,区间加 - 单点查。
第二个部分可以考虑统计贡献,直接在 DFS 序上面维护,单点加 - 区间查。
如果需要在线算法,就可以用维护 \(n\) 个 \(splay\) ,分别维护 \(n\) 种颜色的点的部分 DFS 序。
如果需要离线算法,就可以直接使用整棵树的 DFS 序,然后用 4 个 BIT 分别维护。
时间复杂度 \(O(m\log_2n\log_2l)\) 。
本题的一些有价值的点:
- 对于变化操作的拆分,转化为简单的情形。
- 统计贡献与维护贡献两种思想。
代码
由于这是模拟赛里面的题目,所以没有处理多组数据。
#include <cstdio>
#include <vector>
using namespace std;
typedef long long LL;
#define int LL
const int MAXN = 1e5 + 5, MAXS = MAXN << 1;
template<typename _T>
void read( _T &x )
{
x = 0;char s = getchar();int f = 1;
while( s > '9' || s < '0' ){if( s == '-' ) f = -1; s = getchar();}
while( s >= '0' && s <= '9' ){x = ( x << 3 ) + ( x << 1 ) + ( s - '0' ), s = getchar();}
x *= f;
}
template<typename _T>
void write( _T x )
{
if( x < 0 ){ putchar( '-' ); x = ( ~ x ) + 1; }
if( 9 < x ){ write( x / 10 ); }
putchar( x % 10 + '0' );
}
struct edge
{
int to, nxt;
}Graph[MAXN << 1];
struct oper
{
int typ, pos, nVal, sta;
oper() { typ = pos = nVal = sta = 0; }
oper( int a, int b, int c, int d ) { typ = a, pos = b, nVal = c, sta = d; }
};
//1->add, 0->delete
vector<oper> O[MAXN];
LL ans[MAXN];
int dif[MAXN];
int C[MAXN], L[MAXN];
int head[MAXN], DFN[MAXN], siz[MAXN];
int N, M, cnt, ID, D;
int tot[2]; LL all;
struct BinIndTree
{
int BIT[MAXN];
void up( int &x ) { x += ( x & ( -x ) ); }
void down( int &x ) { x -= ( x & ( -x ) ); }
void update( int x, const int v ) { for( ; x <= N ; up( x ) ) BIT[x] += v; }
int getSum( int x ) { int ret = 0; for( ; x ; down( x ) ) ret += BIT[x]; return ret; }
int query( const int l, const int r ) { return getSum( r ) - getSum( l - 1 ); }
};
struct RtoU : BinIndTree
{
int Q( const int x ) { return getSum( DFN[x] ); }
void upt( const int x, const int v ) { update( DFN[x], v ), update( DFN[x] + siz[x], -v ); };
}R[2];
struct SubT : BinIndTree
{
int Q( const int x ) { return query( DFN[x], DFN[x] + siz[x] - 1 ); }
void upt( const int x, const int v ) { update( DFN[x], v ); }
}S[2];
void addEdge( const int from, const int to )
{
Graph[++ cnt].to = to, Graph[cnt].nxt = head[from];
head[from] = cnt;
}
void init( const int u, const int fa )
{
DFN[u] = ++ ID, siz[u] = 1;
for( int i = head[u], v ; i ; i = Graph[i].nxt )
if( ( v = Graph[i].to ) ^ fa )
init( v, u ), siz[u] += siz[v];
}
int get( const int u, const int t )
{
int a = R[t].Q( u ), b = S[t].Q( u );
return a + b;
}
void launch( oper cur )
{
int u = cur.pos, delt = cur.nVal >> D & 1, val;
if( cur.typ )
{
val = tot[delt ^ 1] - get( u, delt ^ 1 );
R[delt].upt( u, 1 ), S[delt].upt( u, 1 ), tot[delt] ++;
}
else
{
R[delt].upt( u, -1 ), S[delt].upt( u, -1 ), tot[delt] --;
val = - tot[delt ^ 1] + get( u, delt ^ 1 );
}
all += val;
}
signed main()
{
read( N );
for( int i = 1 ; i <= N ; i ++ ) read( C[i] );
for( int i = 1 ; i <= N ; i ++ ) read( L[i] );
for( int i = 1, a, b ; i < N ; i ++ ) read( a ), read( b ), addEdge( a, b ), addEdge( b, a );
init( 1, 0 ), read( M );
for( int i = 1 ; i <= N ; i ++ ) O[C[i]].push_back( oper( 1, i, L[i], 0 ) );
for( int i = 1 ; i <= M ; i ++ )
{
int opt, x, y;
read( opt ), read( x ), read( y );
if( opt == 1 )
O[C[x]].push_back( oper( 0, x, L[x], i ) ),
O[C[x] = y].push_back( oper( 1, x, L[x], i ) );
else
O[C[x]].push_back( oper( 0, x, L[x], i ) ),
O[C[x]].push_back( oper( 1, x, L[x] = y, i ) );
}
for( int i = 1 ; i <= N ; i ++ ) O[C[i]].push_back( oper( 0, i, L[i], M + 1 ) );
for( D = 0 ; D < 20 ; D ++ )
{
for( int i = 0 ; i <= M ; i ++ ) dif[i] = 0;
for( int col = 1 ; col <= N ; col ++ )
{
tot[0] = tot[1] = 0;
int lim = ( int ) O[col].size(), ed;
for( int k = 0, r = 0 ; k < lim ; )
{
for( r = k ; r < lim && O[col][r].sta == O[col][k].sta ; r ++ );
ed = r == lim ? M + 1 : O[col][r].sta;
for( ; k < r ; k ++ ) launch( O[col][k] );
dif[O[col][k - 1].sta] += all, dif[ed] -= all;
}
}
for( int i = 1 ; i <= M ; i ++ ) dif[i] += dif[i - 1];
for( int i = 0 ; i <= M ; i ++ ) ans[i] += ( 1ll << D ) * dif[i];
}
for( int i = 0 ; i <= M ; i ++ ) write( ans[i] ), putchar( '\n' );
return 0;
}
[HDU6793] Tokitsukaze and Colorful Tree的更多相关文章
- 2017 Multi-University Training Contest - Team 1 1003&&HDU 6035 Colorful Tree【树形dp】
Colorful Tree Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)T ...
- hdu6035 Colorful Tree 树形dp 给定一棵树,每个节点有一个颜色值。定义每条路径的值为经过的节点的不同颜色数。求所有路径的值和。
/** 题目:hdu6035 Colorful Tree 链接:http://acm.hdu.edu.cn/showproblem.php?pid=6035 题意:给定一棵树,每个节点有一个颜色值.定 ...
- AtCoder Beginner Contest 133 F Colorful Tree
Colorful Tree 思路: 如果强制在线的化可以用树链剖分. 但这道题不强制在线,那么就可以将询问进行差分,最后dfs时再计算每个答案的修改值, 只要维护两个数组就可以了,分别表示根节点到当前 ...
- HDU 6035 - Colorful Tree | 2017 Multi-University Training Contest 1
/* HDU 6035 - Colorful Tree [ DFS,分块 ] 题意: n个节点的树,每个节点有一种颜色(1~n),一条路径的权值是这条路上不同的颜色的数量,问所有路径(n*(n-1)/ ...
- Colorful tree
cnbb 我被数组清零卡了一天.. 子树改色询问子树颜色数.. 先考虑颜色为x的节点对祖先答案的贡献,那么我们考虑把所有这些节点都搞出来,按dfs序排序,然后考虑每个节点a掌管的祖先是它和按dfs序的 ...
- 2017ACM暑期多校联合训练 - Team 1 1003 HDU 6035 Colorful Tree (dfs)
题目链接 Problem Description There is a tree with n nodes, each of which has a type of color represented ...
- HDU-6035:Colorful Tree(虚树+DP)
这里有三道长得像的题: 一:HDU6036: There is a tree with nn nodes, each of which has a type of color represented ...
- ABC133F - Colorful Tree
ABC133FColorful Tree 题意 给定一颗边有颜色和权值的树,多次询问,每次询问,首先更改颜色为x的边的权值为y,然后输出u到v的距离. 数据都是1e5量级的. 思路 我自己一开始用树链 ...
- HDU6035 Colorful Tree
题目链接:https://vjudge.net/problem/HDU-6035 题目大意: 多样例输入. 对于每一个样例,给出 n \((2 \le n \le 200000)\) 个结点的一棵树, ...
随机推荐
- 路径总和(leetcode 113)
题目描述如下所示: 给定一个二叉树和一个目标和,找到所有从根节点到叶子节点路径总和等于给定目标和的路径.(https://leetcode-cn.com/problems/path-sum-ii/) ...
- Day03_WebCrawler(网络爬虫)
学于黑马和传智播客联合做的教学项目 感谢 黑马官网 传智播客官网 微信搜索"艺术行者",关注并回复关键词"webcrawler"获取视频和教程资料! b站在线视 ...
- matplotlib基础汇总_03
四图 直方图 [直方图的参数只有一个x!!!不像条形图需要传入x,y] hist()的参数 bins 可以是一个bin数量的整数值,也可以是表示bin的一个序列.默认值为10 normed 如果值为T ...
- 教你在 Linux 下时光穿梭
时光穿梭?电影里的桥段吧?良许你又在唬人? 非也非也,良许在这里要给大家介绍 touch 命令,有了它你就可以改变时间戳,达到时光穿梭的目的. touch 命令在我们的工作中使用也相当频繁,我们就由浅 ...
- 【CF115E】Linear Kingdom Races 题解(线段树优化DP)
前言:前辈讲课时设的状态还是有些繁琐,感觉题解设的状态更简洁. -------------- 题目链接 题目大意:给定$n$条道路和$m$场比赛,每个道路修建需要$c_i$,每场比赛需要使用$[l_i ...
- Android SQLite轻量级数据库(简单介绍)
SQLite它是相当于嵌入到安卓里的一个小数据库吧, 它也可以使用SQL语句进行数据库的增删改查操作,但是是SQL1992的语句. 然后SQLite也有自己的语句,但是学过SQL的应该都会发现,它比较 ...
- SpringMvc接收multipart/form-data 传输的数据 及 PostMan各类数据类型的区别
前段时间遇到一个问题,在spring mvc 服务端接收post请求时,通过html 表单提交的时候,服务端能够接收到参数的值.但是使用httpclient4.3构造post请求,却无法接收到参数的值 ...
- TCP学习指北
限于博主水平有限不敢说指南,但应该能够避免刚学TCP的同学出现找不着北的情况. TCP与UDP的区别 区别: UDP是无连接的,而TCP是面向连接的,传数据前要先建立连接. UDP可以一对多,多对多通 ...
- JS学习第一天
JS的三种引入方式: 内联:在标签属性中引入javascript:js代码 <a href="javascript:("helloworld")"& ...
- 如何实现数据库CDP,即数据库连续数据保护
备份可以分为定期备份和实时备份.定期备份与实时备份相比存在两大劣势:一是备份需要时间窗口,对于很多24小时业务运行的机构,线上业务不允许有过多的业务系统停机去进行数据备份:二是定期备份无法保证数据丢失 ...