Solution -「LOCAL」Burning Flowers
灼之花好评,条条生日快乐(假装现在 8.15)!
\(\mathcal{Description}\)
给定一棵以 \(1\) 为根的树,第 \(i\) 个结点有颜色 \(c_i\) 和光亮值 \(l_i\),定义树的权值为:
\]
现有 \(m\) 次修改,每次修改某点的颜色或光亮值,求出每次修改后树的权值。
\(n,m\le10^5\),\(c_i\le n\),\(l_i<2^{20}\)。
\(\mathcal{Solution}\)
分颜色贡献,位运算拆位,基本姿势 w!
假定树的结点全部同色且光亮值为 \(0/1\),考虑点 \(u\) 的贡献,显然先加上所有能与它异或成 \(1\) 的结点个数,再减去在子树内或在祖先上的结点个数。而从动态修改的角度,两者都能使用 BIT(树状数组)维护!
所以,枚举每个颜色 \(c\),对于每一个 bit,维护两个 BIT,分别保存子树内颜色为 \(c\) 且当前 bit 为 \(1\) 的结点个数和祖先上颜色为 \(c\) 且当前 bit 为 \(1\) 的结点个数,处理修改就暴力除去贡献再更新贡献即可。
复杂度 \(\mathcal O(20(n+m)\log n)\)。
\(\mathcal{Code}\)
#include <cstdio>
#include <vector>
#include <iostream>
typedef long long LL;
inline char fgc () {
static char buf[1 << 17], *p = buf, *q = buf;
return p == q && ( q = buf + fread ( p = buf, 1, 1 << 17, stdin ), p == q ) ? EOF : *p ++;
}
inline int rint () {
int x = 0; char s = fgc ();
for ( ; s < '0' || '9' < s; s = fgc () );
for ( ; '0' <= s && s <= '9'; s = fgc () ) x = x * 10 + ( s ^ '0' );
return x;
}
inline void wint ( const LL x ) {
if ( 9 < x ) wint ( x / 10 );
putchar ( x % 10 ^ '0' );
}
const int MAXN = 1e5;
int n, m, ecnt, head[MAXN + 5], col[MAXN + 5], val[MAXN + 5];
int dfc, dep[MAXN + 5], dfn[MAXN + 5], siz[MAXN + 5];
LL ans[MAXN + 5];
struct Edge { int to, nxt; } graph[MAXN * 2 + 5];
struct BinaryIndexTree {
int val[MAXN + 5];
inline int lowbit ( const int x ) { return x & -x; }
inline void update ( int x, const int k ) { for ( ; x <= n; x += lowbit ( x ) ) val[x] += k; }
inline int sum ( int x ) { int ret = 0; for ( ; x; x -= lowbit ( x ) ) ret += val[x]; return ret; }
inline int sum ( const int l, const int r ) { return sum ( r ) - sum ( l - 1 ); }
} facnt, soncnt, fabit[20], sonbit[20];
struct BitBucket {
int all, cnt[20];
inline void clear () { all = 0; for ( int i = 0; i < 20; ++ i ) cnt[i] = 0; }
inline void update ( const int x, const int k ) {
all += k;
for ( int i = 0; 1 << i <= x; ++ i ) {
if ( ( x >> i ) & 1 ) {
cnt[i] += k;
}
}
}
inline LL query ( const int x ) {
LL ret = 0;
for ( int i = 0; i < 20; ++ i ) {
if ( ( x >> i ) & 1 ) ret += 1ll * ( all - cnt[i] ) << i;
else ret += 1ll * cnt[i] << i;
}
return ret;
}
} buc;
struct Event {
int u, val, time, type;
Event () {}
Event ( const int tu, const int tv, const int tti, const int tty ):
u ( tu ), val ( tv ), time ( tti ), type ( tty ) {}
}; std::vector<Event> evt[MAXN + 5];
inline void link ( const int s, const int t ) {
graph[++ ecnt].to = t, graph[ecnt].nxt = head[s];
head[s] = ecnt;
}
inline void init ( const int u, const int f ) {
siz[u] = 1, dfn[u] = ++ dfc, dep[u] = dep[f] + 1;
for ( int i = head[u], v; i; i = graph[i].nxt ) {
if ( ( v = graph[i].to ) ^ f ) {
init ( v, u ), siz[u] += siz[v];
}
}
}
inline void initEvent () {
m = rint ();
for ( int i = 1; i <= n; ++ i ) evt[col[i]].push_back ( Event ( i, val[i], 0, 1 ) );
for ( int i = 1, op, u, t; i <= m; ++ i ) {
op = rint (), u = rint (), t = rint ();
evt[col[u]].push_back ( Event ( u, val[u], i, 0 ) );
if ( op & 1 ) evt[col[u] = t].push_back ( Event ( u, val[u], i, 1 ) );
else evt[col[u]].push_back ( Event ( u, val[u] = t, i, 1 ) );
}
for ( int i = 1; i <= n; ++ i ) evt[col[i]].push_back ( Event ( i, val[i], m + 1, 0 ) );
}
inline LL queryFa ( const int u, const int val ) {
LL ret = 0;
int all = facnt.sum ( dfn[u] );
for ( int i = 0; i < 20; ++ i ) {
if ( ( val >> i ) & 1 ) ret += 1ll * ( all - fabit[i].sum ( dfn[u] ) ) << i;
else ret += 1ll * fabit[i].sum ( dfn[u] ) << i;
}
return ret;
}
inline void updateFa ( const int u, const int val, const int k ) {
int l = dfn[u], r = dfn[u] + siz[u];
facnt.update ( l, k ), facnt.update ( r, -k );
for ( int i = 0; 1 << i <= val; ++ i ) {
if ( ( val >> i ) & 1 ) {
fabit[i].update ( l, k );
fabit[i].update ( r, -k );
}
}
}
inline LL querySon ( const int u, const int val ) {
LL ret = 0;
int l = dfn[u], r = dfn[u] + siz[u] - 1;
int all = soncnt.sum ( l, r );
for ( int i = 0; i < 20; ++ i ) {
if ( ( val >> i ) & 1 ) ret += 1ll * ( all - sonbit[i].sum ( l, r ) ) << i;
else ret += 1ll * sonbit[i].sum ( l, r ) << i;
}
return ret;
}
inline void updateSon ( const int u, const int val, const int k ) {
soncnt.update ( dfn[u], k );
for ( int i = 0; 1 << i <= val; ++ i ) {
if ( ( val >> i ) & 1 ) {
sonbit[i].update ( dfn[u], k );
}
}
}
int main () {
freopen ( "cop.in", "r", stdin );
freopen ( "cop.out", "w", stdout );
n = rint ();
for ( int i = 1; i <= n; ++ i ) col[i] = rint ();
for ( int i = 1; i <= n; ++ i ) val[i] = rint ();
for ( int i = 1, u, v; i < n; ++ i ) {
u = rint (), v = rint ();
link ( u, v ), link ( v, u );
}
init ( 1, 0 ), initEvent ();
for ( int c = 1; c <= n; ++ c ) {
buc.clear ();
LL sum = 0, ill = 0;
for ( int i = 0; i ^ evt[c].size (); ++ i ) {
Event cur ( evt[c][i] );
if ( cur.type ) {
sum += buc.query ( cur.val ), buc.update ( cur.val, 1 );
ill += queryFa ( cur.u, cur.val ), updateFa ( cur.u, cur.val, 1 );
ill += querySon ( cur.u, cur.val ), updateSon ( cur.u, cur.val, 1 );
} else {
sum -= buc.query ( cur.val ), buc.update ( cur.val, -1 );
ill -= queryFa ( cur.u, cur.val ), updateFa ( cur.u, cur.val, -1 );
ill -= querySon ( cur.u, cur.val ), updateSon ( cur.u, cur.val, -1 );
}
if ( cur.time <= m ) {
ans[cur.time] += sum - ill;
ans[i + 1 == ( int ) evt[c].size () ? m + 1 : evt[c][i + 1].time] -= sum - ill;
}
}
}
wint ( ans[0] ), putchar ( '\n' );
for ( int i = 1; i <= m; ++ i ) printf ( "%lld", ans[i] += ans[i - 1] ), putchar ( '\n' );
return 0;
}
\(\mathcal{Details}\)
考场上卡常 \(\mathcal O(n(m+\log n))\) 骗到 \(50pts\) 心满意足 www。
这种类似离线的处理方法要感知到位,毕竟兔子这种码力持久化啊虚树啊都不可能考场敲出来 qwq(自暴自弃。
Solution -「LOCAL」Burning Flowers的更多相关文章
- Solution -「LOCAL」二进制的世界
\(\mathcal{Description}\) OurOJ. 给定序列 \(\{a_n\}\) 和一个二元运算 \(\operatorname{op}\in\{\operatorname{ ...
- Solution -「LOCAL」大括号树
\(\mathcal{Description}\) OurTeam & OurOJ. 给定一棵 \(n\) 个顶点的树,每个顶点标有字符 ( 或 ).将从 \(u\) 到 \(v\) ...
- Solution -「LOCAL」过河
\(\mathcal{Description}\) 一段坐标轴 \([0,L]\),从 \(0\) 出发,每次可以 \(+a\) 或 \(-b\),但不能越出 \([0,L]\).求可达的整点数. ...
- Solution -「LOCAL」Drainage System
\(\mathcal{Description}\) 合并果子,初始果子的权值在 \(1\sim n\) 之间,权值为 \(i\) 的有 \(a_i\) 个.每次可以挑 \(x\in[L,R]\) ...
- Solution -「LOCAL」画画图
\(\mathcal{Description}\) OurTeam. 给定一棵 \(n\) 个点的树形随机的带边权树,求所有含奇数条边的路径中位数之和.树形生成方式为随机取不连通两点连边直到全 ...
- Solution -「LOCAL」ZB 平衡树
\(\mathcal{Description}\) OurOJ. 维护一列二元组 \((a,b)\),给定初始 \(n\) 个元素,接下来 \(m\) 次操作: 在某个位置插入一个二元组: 翻 ...
- Solution -「LOCAL」舟游
\(\mathcal{Description}\) \(n\) 中卡牌,每种三张.对于一次 \(m\) 连抽,前 \(m-1\) 次抽到第 \(i\) 种的概率是 \(p_i\),第 \(m\) ...
- Solution -「LOCAL」充电
\(\mathcal{Description}\) 给定 \(n,m,p\),求序列 \(\{a_n\}\) 的数量,满足 \((\forall i\in[1,n])(a_i\in[1,m])\l ...
- Solution -「LOCAL」「cov. 牛客多校 2020 第五场 C」Easy
\(\mathcal{Description}\) Link.(完全一致) 给定 \(n,m,k\),对于两个长度为 \(k\) 的满足 \(\left(\sum_{i=0}^ka_i=n\r ...
随机推荐
- Kubernetes API作为权威接口,Kubernetes将成为软件的通用控制平面
1创新之处在于API这是有关 Kubernetes的两部分系列中的第一篇.第一部分是一个答案:影响Kubernetes设计的关键思想是什么?Kubernetes会将它与其他平台区分开来吗?第二部分是关 ...
- JavaScript的执行过程(深入执行上下文、GO、AO、VO和VE等概念)
JavaScript的执行过程 前言 编写一段JavaScript代码,它是如何执行的呢?简单来说,JS引擎在执行JavaScript代码的过程中需要先解析再执行.那么在解析阶段JS引擎又会进行哪些操 ...
- 【数据结构】图的基本操作——图的构造(邻接矩阵,邻接表),遍历(DFS,BFS)
邻接矩阵实现如下: /* 主题:用邻接矩阵实现 DFS(递归) 与 BFS(非递归) 作者:Laugh 语言:C++ ***************************************** ...
- GeoServer介绍
GeoServer本质上是一个地图服务器,它是遵循OpenGIS Web 服务器规范的J2EE实现,通过它可以方便的将地图数据发布为地图服务,实现地理空间数据在用户之间的共享.另外,它也提供了相应的接 ...
- [javaweb]strut2-001漏洞分析
Strut2-001 漏洞描述 框架解析JSP页面标签时会对用户输入的Value值获取,在获取对应的Value值中递归解析%{.}造成了二次解析,最终触发表达式注入漏洞,执行任意代码 影响版本 2.0 ...
- JAVA实现对阿里云DNS的解析管理
1.阿里云DNS的SDK依赖 <dependency> <groupId>com.aliyun</groupId> <artifactId>tea-op ...
- gorm创建记录
1. 简单创建记录 user := User{Name: "李四", Age: 88, Birthday: time.Now()} ret := db.Create(&u ...
- 元编程 (meta-programming)
元编程 (meta-programming) 术语 meta:英语前缀词根,来源于希腊文.中国大陆一般翻译成"元". 在逻辑学中,可以理解为:关于X的更高层次,同时,这个更高层次的 ...
- vue和react 相似和区别
相似之处 他们都是JavaScript的UI框架,专注于创造前端的富应用 不同于早期的JavaScript框架"功能齐全",Reat与Vue只有框架的骨架,其他的功能如路由.状态管 ...
- How to check in Windows if you are using UEFI
You might be wondering if Windows is using UEFI or the legacy BIOS, it's easy to check. Just fire up ...