[WC 2013]糖果公园
Description
给你一棵 \(n\) 个节点,有 \(m\) 种颜色的树。每个节点上有一个颜色。定义一条树上路径的价值为
\[\sum_c V_c(\sum_{i=1}^{tim_c}W_i)\]
其中 \(V,W\) 已经给出, \(tim_c\) 表示路径上 \(c\) 颜色的节点数。
现在给出 \(q\) 个操作,让你实现:
- 修改节点颜色;
- 询问树上路径的价值。
\(1\leq n,m,q\leq 100000\)
Solution
如果这题出在序列上而不是在树上,很容易用莫队求解。
考虑用类似的方法,我们将树分块,采用[SCOI 2005]王室联邦的方法。
对于树上分块的复杂度和块的大小的选取可以参见ljh的博客,这里摘出了一些:
设 \(block_{num}\) 为块数, \(block_{size}\) 为块的大小,则有 \(block_{num}\times block_{size}=n\) ,在证明中我们假设 \(n,q\) 同阶。
设块对 \((block_i,block_j)\) ,易知这样的块对不会超过 \(block_{size}^2\) 个。
对于块对内的操作:我们考虑总复杂度,左端点共移动至多 \(O(q\times block_{size})\) ,右端点亦是。时间共移动至多 \(O(block_{num}^2\times q)\) 。故这一部分的复杂度为 \(O(n\times(block_{size}+block_{num}^2))\) 。
对于块与块之间的操作,不超过 \(block_{num}^2\) 次:左端第移动一次,最多 \(O(n)\) ,右端点亦是如此。时间最多移动 \(O(q)=O(n)\) 。故这一部分复杂度为 \(O(block_{num}^2\times n)\) 。
故总复杂度为 \(O(n\times(block_{size}+block_{num}^2))\) 。
可以证明当 \(block_{size}=n^{\frac{2}{3}}\) 时, \(block_{num}=n^{\frac{1}{3}}\) ,复杂度最优,为 \(O(n^{\frac{5}{3}})\) 。
至于莫队的操作,就是将序列中移动左右端点变成在树上移动路径的两个端点。对于修改,我们同样是模拟时间倒流和消逝。
那么怎么去移动结点来保证提取出路径?
考虑我们树上的所有结点,实际上可以认为是 \(0/1\) 状态——计入答案或者未计入答案。
考虑用类似于异或的思想来执行操作,比如:计入答案再从答案中去掉,等于异或了两次 \(1\) ,就等于原来的数。假设这次的起点、终点为 \(u,v\) ,上次为 \(x,y\) ,那么可以对 \(x\) 到 \(u\) 的路径、 \(v\) 到 \(y\) 的路径进行一次取 \(xor\) 操作。注意的是对 \(lca\) 不做处理,这样就能保证每次操作之后图上打上标记的点只在 \((u,lca)\) 和 \((v,lca)\) 的路径上(不包括 \(lca\) )。
Code
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5;
int n, m, q, v[N+5], w[N+5], c[N+5], tq, tc, s[N+5], tol, pre[N+5], tim[N+5];
int dfn[N+5], times, size[N+5], son[N+5], tp[N+5], fa[N+5], dep[N+5], rev[N+5];
long long ans[N+5], sum;
struct tt {int to, next; }edge[(N<<1)+5];
int path[N+5], top, blocks[N+5], block_size, cnt;
struct operation {
int l, r, p, id;
bool operator < (const operation &b) const {
if (blocks[l] != blocks[b.l]) return blocks[l] < blocks[b.l];
if (blocks[r] != blocks[b.r]) return blocks[r] < blocks[b.r];
return id < b.id;
}
}qry[N+5], ch[N+5];
void add(int u, int v) {edge[++top] = (tt){v, path[u]}, path[u] = top; }
void dfs1(int u, int father, int depth) {
int bot = tol;
dfn[u] = ++times, size[u] = 1, dep[u] = depth, fa[u] = father;
for (int i = path[u], v; i; i = edge[i].next)
if ((v = edge[i].to) != father) {
dfs1(v, u, depth+1);
size[u] += size[v];
if (size[v] > size[son[u]]) son[u] = v;
if (tol-bot >= block_size) {
++cnt;
while (tol != bot) blocks[s[tol--]] = cnt;
}
}
s[++tol] = u;
}
void dfs2(int u, int top) {
tp[u] = top;
if (son[u]) dfs2(son[u], top);
for (int i = path[u]; i; i = edge[i].next)
if (edge[i].to != son[u] && edge[i].to != fa[u])
dfs2(edge[i].to, edge[i].to);
}
int get_lca(int u, int v) {
while (tp[u] != tp[v]) {
if (dep[tp[u]] < dep[tp[v]]) swap(u, v);
u = fa[tp[u]];
}
return dep[u] < dep[v] ? u : v;
}
void reverse(int x) {
if (rev[x]) sum -= 1ll*v[c[x]]*w[tim[c[x]]], --tim[c[x]];
else ++tim[c[x]], sum += 1ll*v[c[x]]*w[tim[c[x]]];
rev[x] ^= 1;
}
void upd(int x, int y) {
if (rev[x]) reverse(x), c[x] = y, reverse(x);
else c[x] = y;
}
void move(int x, int y) {
while (x != y) {
if (dep[x] < dep[y]) swap(x, y);
reverse(x); x = fa[x];
}
}
void work() {
scanf("%d%d%d", &n, &m, &q); block_size = pow(n, 0.6667);
for (int i = 1; i <= m; i++) scanf("%d", &v[i]);
for (int i = 1; i <= n; i++) scanf("%d", &w[i]);
for (int i = 1, u, v; i < n; i++) {
scanf("%d%d", &u, &v); add(u, v), add(v, u);
}
dfs1(1, 0, 1); dfs2(1, 1);
while (tol) blocks[s[tol--]] = cnt;
for (int i = 1; i <= n; i++) scanf("%d", &c[i]), pre[i] = c[i];
for (int i = 1, opt, x, y; i <= q; i++) {
scanf("%d%d%d", &opt, &x, &y);
if (opt == 0) ch[++tc] = (operation){x, y, pre[x], 0}, pre[x] = y;
else {
if (dfn[x] > dfn[y]) swap(x, y);
qry[++tq] = (operation){x, y, tc, tq};
}
}
sort(qry+1, qry+tq+1);
int curt = 0, curl = 1, curr = 1;
for (int i = 1; i <= tq; i++) {
while (curt < qry[i].p) ++curt, upd(ch[curt].l, ch[curt].r);
while (curt > qry[i].p) upd(ch[curt].l, ch[curt].p), --curt;
move(curl, qry[i].l); curl = qry[i].l;
move(curr, qry[i].r); curr = qry[i].r;
int lca = get_lca(curl, curr);
reverse(lca);
ans[qry[i].id] = sum;
reverse(lca);
}
for (int i = 1; i <= tq; i++) printf("%lld\n", ans[i]);
}
int main() {work(); return 0; }
[WC 2013]糖果公园的更多相关文章
- 【BZOJ】3052: [wc2013]糖果公园 树分块+带修改莫队算法
[题目]#58. [WC2013]糖果公园 [题意]给定n个点的树,m种糖果,每个点有糖果ci.给定n个数wi和m个数vi,第i颗糖果第j次品尝的价值是v(i)*w(j).q次询问一条链上每个点价值的 ...
- UOJ #58 【WC2013】 糖果公园
题目链接:糖果公园 听说这是一道树上莫队的入门题,于是我就去写了--顺便复习了一下莫队的各种姿势. 首先,我们要在树上使用莫队,那么就需要像序列一样给树分块.这个分块的过程就是王室联邦这道题(vfle ...
- UOJ58 【WC2013】糖果公园
本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/ ...
- 【BZOJ-3052】糖果公园 树上带修莫队算法
3052: [wc2013]糖果公园 Time Limit: 200 Sec Memory Limit: 512 MBSubmit: 883 Solved: 419[Submit][Status] ...
- bzoj 3052: [wc2013]糖果公园 带修改莫队
3052: [wc2013]糖果公园 Time Limit: 250 Sec Memory Limit: 512 MBSubmit: 506 Solved: 189[Submit][Status] ...
- 【WC2013】糖果公园
Candyland 有一座糖果公园,公园里不仅有美丽的风景.好玩的游乐项目,还有许多免费糖果的发放点,这引来了许多贪吃的小朋友来糖果公园玩. 糖果公园的结构十分奇特,它由 nn 个游览点构成,每个游览 ...
- 洛谷 P4074 [WC2013]糖果公园 解题报告
P4074 [WC2013]糖果公园 糖果公园 树上待修莫队 注意一个思想,dfn序处理链的方法,必须可以根据类似异或的东西,然后根据lca分两种情况讨论 注意细节 Code: #include &l ...
- 【Luogu P4074】[WC2013]糖果公园(树上带修改莫队)
题目描述 Candyland 有一座糖果公园,公园里不仅有美丽的风景.好玩的游乐项目,还有许多免费糖果的发放点,这引来了许多贪吃的小朋友来糖果公园游玩. 糖果公园的结构十分奇特,它由 \(n\) 个游 ...
- BZOJ3052:[WC2013]糖果公园(树上莫队)
Description Input Output Sample Input 4 3 51 9 27 6 5 12 33 13 41 2 3 21 1 21 4 20 2 11 1 21 4 2 Sam ...
随机推荐
- 云计算--网络原理与应用--20171123--网络地址转换NAT
NAT的概述 NAT的配置 实验 一. NAT的概述 NAT(Network address translation,网络地址转换)通过将内部网络的的私有地址翻译成全球唯一的共有网络IP地址,是内部网 ...
- JavaScript(简介)【Javascript历史】
学习一门知识应该了解其背景,很多人认为会用就行,起初我也是这么认为的,但后来才知道对起源的了解也很必要,从事javascript开发5年,今天开始总结一些笔记,分享下. 一.什么是JavaScript ...
- 记录python接口自动化测试--requests使用和基本方法封装(第一目)
之前学习了使用jmeter+ant做接口测试,并实现了接口的批量维护管理(大概500多条用例),对"接口"以及"接口测试"有了一个基础了解,最近找了一些用pyt ...
- Beta冲刺NO.7
Beta冲刺 第七天 昨天的困难 昨天的困难在一些多表查询上,不熟悉hibernate的套路,走了很多弯路. 第一次使用图表插件,在图表的显示问题上花了一定的时间. 对于页面绑定和后台数据自动填充的理 ...
- 201621123062《java程序设计》第八周作业总结
1. 本周学习总结 以你喜欢的方式(思维导图或其他)归纳总结集合相关内容. 思维导图: 2. 书面作业 2.1ArrayList代码分析 2.1.1 解释ArrayList的contains源代码 源 ...
- c语言博客第二次作业
一.PTA实验作业 题目1:计算分段函数[2] 1.实验代码 { double x,y; scanf("%lf",&x); if(x>=0) { y=pow(x,0. ...
- Linux下vim上编辑实现进度条
1.效果展示: 进度条,先来看一个效果: 这是进度结果,模拟实现了进度条的前进.百分比的现实.以及稍微的动画特效. 2.原理描述: 因为Linux系统下的输出有缓存,如果及时刷新显示,就可以得到我们想 ...
- Django Haystack 全文检索与关键词高亮
Django Haystack 简介 django-haystack 是一个专门提供搜索功能的 django 第三方应用,它支持 Solr.Elasticsearch.Whoosh.Xapian 等多 ...
- Java语言基础组成
写完才发现,这个博客不提供目录这个功能,真是想骂爹了...... 目录 关键字 标识符 注释 常量和变量 运算符 语句 函数 数组 1.关键字 描述:刚刚开始学这个的时候,真是傻傻分不清楚,不过没关系 ...
- SQL之Left Join 关联条件的探讨
在测试工作中,有时需要测试数据库数据经过sql计算后的结果是否满足某一功能查询得到的返回值. 针对某些需要功能需要联查多张表,此时 关联 的作用就异常重要了,而针对多表关联,其中 关联条件的重要性不言 ...