link

题目大意:给一个树,树上每个点都有一种颜色,每个颜色都有一个收益

每次修改一个点上的颜色

或询问一条链上所有颜色第i次遇到颜色j可以获得w[i]*v[j]的价值,求链上价值和

题解:树上带修莫队

按照带修莫队那套理论,我们要把树分成若干个块满足每个块内联通

把询问按照左端点所在块为第一关键字,右端点所在块为第二关键字,时间为第三关键字排序

假设块的大小为 \(B\)

则换块次数为 \(O((\frac{N}{B})^2)\) ,每次换块复杂度 \(O(n)\)

不换块每块内时间维度修改复杂度为 \(O(q)\),总共为 $ O((\frac{N}{B})^2q)$

每次询问块内改节点是 \(O(B)\),所以总复杂度(如果默认n,q同阶) 为 \(O(NB+\frac{N^3}{B^2})\),发现取 \(B=N^{2/3}\) 时值最小,为 \(O(N^{5/3})\)

我们每次维护当前 x 到 rt 路径上点 和 y 到 rt 路径上点 的集合对称差(差不多就是异或)(开一个bool数组记录某个点是否被维护)(说白了就是维护x到y路径除了lca的所有点)

从 (x,y) 到 (nx,ny) 转移时,我们只需要改变x,y,nx,ny到rt的值,其实就是x到nx路径上除了lca的所有点以及y到ny路径上除了lca以外的所有点(比较方便维护)

求答案时候,我们临时把lca的值加进去,最后再减回来就行

注意w前缀和要开long long,否则会炸

#include <cmath>
#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std; struct fuck { int x, y, id; } a[200010];
int n, m, q, sz, top, tot, bcnt;
int v[200010], bid[200010], bucket[200010];
int fa[200010][19], s[200010], c[200010], tmp[200010];
vector<int> out[200010];
int pos[200010], from[200010], to[200010], depth[200010];
bool in[200010];
long long sum, ans[200010], w[200010]; bool fucked(const fuck &a, const fuck &b)
{
if (bid[a.x] != bid[b.x]) return bid[a.x] < bid[b.x];
if (bid[a.y] != bid[b.y]) return bid[a.y] < bid[b.y];
return a.id < b.id;
} void dfs(int x)
{
int tmp = top;
for (int i : out[x]) if (fa[x][0] != i)
{
fa[i][0] = x, depth[i] = depth[x] + 1, dfs(i);
if (top - tmp >= sz) { bcnt++; while (top != tmp) bid[s[top--]] = bcnt; }
}
s[++top] = x;
} int lca(int x, int y)
{
if (depth[x] < depth[y]) swap(x, y);
for (int i = 18; i >= 0; i--) if (depth[fa[x][i]] >= depth[y]) x = fa[x][i];
if (x == y) return x;
for (int i = 18; i >= 0; i--) if (fa[x][i] != fa[y][i]) x = fa[x][i], y = fa[y][i];
return fa[x][0];
} void del(int x) { sum -= v[x] * w[bucket[x]]; bucket[x]--; sum += v[x] * w[bucket[x]]; }
void add(int x) { sum -= v[x] * w[bucket[x]]; bucket[x]++; sum += v[x] * w[bucket[x]]; }
void chenge(int x) { if (in[x]) del(c[x]); else add(c[x]); in[x] ^= 1; }
void chenge(int x, int y)
{
int lc = lca(x, y);
while (x != lc) chenge(x), x = fa[x][0];
while (y != lc) chenge(y), y = fa[y][0];
} int main()
{
scanf("%d%d%d", &n, &m, &q), sz = cbrt(n), sz = sz * sz;
for (int i = 1; i <= m; i++) scanf("%d", &v[i]);
for (int i = 1; i <= n; i++) scanf("%lld", &w[i]), w[i] += w[i - 1];
for (int x, y, i = 1; i < n; i++) scanf("%d%d", &x, &y), out[x].push_back(y), out[y].push_back(x);
for (int i = 1; i <= n; i++) scanf("%d", &c[i]), tmp[i] = c[i];
depth[1] = 1, dfs(1); if (top == 0) { top++; } while (top) bid[s[top--]] = bcnt;
for (int j = 1; j <= 18; j++) for (int i = 1; i <= n; i++) fa[i][j] = fa[fa[i][j - 1]][j - 1];
for (int opd, x, y, i = 1; i <= q; i++)
{
scanf("%d%d%d", &opd, &x, &y);
if (opd) { if (bid[x] > bid[y]) { swap(x, y); } a[++tot] = (fuck){x, y, i}; }
else pos[i] = x, from[i] = tmp[x], tmp[x] = y, to[i] = y;
}
sort(a + 1, a + 1 + tot, fucked);
for (int x = 1, y = 1, t = 0, i = 1; i <= tot; i++)
{
chenge(x, a[i].x), chenge(y, a[i].y), x = a[i].x, y = a[i].y;
for (; t < a[i].id; t++) if (pos[t]) { c[pos[t]] = to[t]; if (in[pos[t]]) del(from[t]), add(to[t]); }
for (; t > a[i].id; t--) if (pos[t]) { c[pos[t]] = from[t]; if (in[pos[t]]) del(to[t]), add(from[t]); }
add(c[lca(x, y)]), ans[a[i].id] = sum, del(c[lca(x, y)]);
}
for (int i = 1; i <= q; i++) if (pos[i] == 0) printf("%lld\n", ans[i]);
return 0;
}

luogu4074 [WC2013]糖果公园(树上带修莫队)的更多相关文章

  1. LUOGU P4074 [WC2013]糖果公园 (树上带修莫队)

    传送门 解题思路 树上带修莫队,搞了两天..终于开O2+卡常大法贴边过了...bzoj上跑了183s..其实就是把树上莫队和带修莫队结合到一起,首先求出括号序,就是进一次出一次那种的,然后如果求两个点 ...

  2. 【BZOJ-3052】糖果公园 树上带修莫队算法

    3052: [wc2013]糖果公园 Time Limit: 200 Sec  Memory Limit: 512 MBSubmit: 883  Solved: 419[Submit][Status] ...

  3. [WC2013][luogu4074] 糖果公园 [树上带修改莫队]

    题面: 传送门 思路: 一道实现起来细节比较恶心的题目 但是其实就是一个裸的树上带修改莫队 好像树上莫队也出不了什么结合题目,不像序列莫队天天结合AC自动机.后缀数组...... 莫队学习请戳这里:莫 ...

  4. BZOJ3052: [wc2013]糖果公园【树上带修莫队】

    Description Input Output Sample Input Sample Input Sample Output 84 131 27 84 HINT 思路 非常模板的树上带修莫队 真的 ...

  5. BZOJ 3052/Luogu P4074 [wc2013]糖果公园 (树上带修莫队)

    题面 中文题面,难得解释了 BZOJ传送门 Luogu传送门 分析 树上带修莫队板子题... 开始没给分块大小赋初值T了好一会... CODE #include <bits/stdc++.h&g ...

  6. BZOJ 4129 Haruna’s Breakfast ( 树上带修莫队 )

    题面 求树上某路径上最小的没出现过的权值,有单点修改 添加链接描述 分析 树上带修莫队板题,问题是怎么求最小的没出现过的权值. 因为只有nnn个点,所以没出现过的最小值一定在[0,n][0,n][0, ...

  7. bzoj4129 Haruna’s Breakfast 树上带修莫队+分块

    题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=4129 题解 考虑没有修改的序列上的版本应该怎么做: 弱化的题目应该是这样的: 给定一个序列,每 ...

  8. BZOJ 3052 树上带修莫队

    思路: 就是把带修莫队移到了树上 块的大小开到(n^2/3)/2 比较好- 这是一个卡OJ好题 //By SiriusRen #include <cmath> #include <c ...

  9. BZOJ3052(树上带修莫队)

    树上莫队的基本思路是把树按dfs序分块,然后先按x所在块从小到大排序,再按y所在块从小到大排序,处理询问即可. 这道题带修改,再加一个时间维即可. 设块大小为T,那么时间复杂度为$O(nT+\frac ...

随机推荐

  1. 在 Windows Azure 上设计多租户应用程序

    作者:Suren Machiraju 和 Ralph Squillace 审校:Christian Martinez.James Podgorski.Valery Mizonov 和 Michael ...

  2. 15-Call to your teacher(有向图的连通判断)

    链接:https://www.nowcoder.net/acm/contest/76/F来源:牛客网 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32768K,其他语言65536K ...

  3. LoadRunner11学习记录二 -- 进行cookie模拟

    1.LoadRunner录制打开一个网页的脚本,会生成脚本夹杂迅雷,迅雷看看,百度等链接地址,这是因为ie打开之后会加载未禁用的加载项.需要把相关的加载项禁用掉. 禁用ie加载项步骤,工具--管理加载 ...

  4. (转)C#中的 Interfaces (For 初学者们)

    http://blog.sina.com.cn/s/blog_574c993d0100d59n.html

  5. [GO]通道的关闭

    并不是往通道里放多少次数据,就必须取多次少数据的(之前的例子都是放3次取3次,放10次取10次),我们可以做一个操作,当子协程没有新放入的时候,主协程不再去取,这就是关闭通道 package main ...

  6. /var/run/yum.pid被锁定

    当执行yum update时出现: /var/run/yum.pid已被锁定,PID为1610的另一个程序正在运行. 另外一个程序锁定了yum:等待它退出...... 解决办法 rm -f /var/ ...

  7. Introducing .NET Standard

    https://blogs.msdn.microsoft.com/dotnet/2016/10/18/the-week-in-net-bond-the-gallery/ .NET Standard s ...

  8. 【小梅哥SOPC学习笔记】给NIOS II CPU增加看门狗定时器并使用

    给NIOS II CPU增加看门狗定时器并使用 配置看门狗定时器: 1. 设置计时溢出时间为1秒 2. 计数器位宽为32位 3. 勾选No Start/Stop control bits 4. 勾选F ...

  9. Reporting Service服务SharePoint集成模式安装配置(9、PowerPivot for SharePoint 安装配置详细)

    PowerPivot for SharePoint 增加了对发布到 SharePoint 中的 PowerPivot 工作簿的协作和文档管理支持. PowerPivot for SharePoint ...

  10. js和C# 时间日期格式转换

    下午在搞MVC和EXTJS的日期格式互相转换遇到了问题,我们从.NET服务器端序列化一个DateTime对象的结果是一个字符串格式,如 '/Date(1335258540000)/' 这样的字串. 整 ...