题目链接:BZOJ - 3052

题目分析

这道题就是非常经典的树上莫队了,并且是带修改的莫队。

带修改的莫队:将询问按照 左端点所在的块编号为第一关键字,右端点所在的块为第二关键字,位于第几次修改之后为第三关键字 排序。

我们将块的大小设置在 n^(2/3) ,这样一共有 n^(1/3) 个块。最后算法的总复杂度会是 n^(5/3) 。

每一次如何从上一个询问转移来呢?

假设上一个询问是 (lx, ly, lt) ,这次的询问是 (x, y, t) 。t 代表是在第 t 次修改操作之后。

首先先移动 t ,如果 t > lt ,那么就将 (lt+1, t) 的修改操作都做一次。如果 t < lt, 就从 t 开始撤销修改操作,一直撤销到 lt+1 。为了能够撤销修改操作,我们需要预处理每次修改操作修改的位置原来是什么颜色。

然后就是移动树上路径了,从 (lx, ly) 到 (x, y) 。这个有一个经典的做法。

我们用 S(a, b) 表示从 a 到 b 的路径上的所有点。我们不直接维护 S(x, y) 的路径上的点,而是维护一个 T(x, y),即 S(x, y) 的路径上的点除去 LCA(x, y) 。

这样从 T(lx, ly) 转移到 T(x, y) 需要先转移到 T(x, ly),再转移到 T(x, y) 。

从 T(lx, ly) 到 T(x, ly) : 我们用 xor 表示两个集合的对称差,就是出现两次的就会抵消。

那么 T(lx, ly) = S(lx, Root) xor S(ly, Root)

T(x, ly) = S(x, Root) xor S(ly, Root)

我们将上面两个式子的两边分别 xor 起来。

T(lx, ly) xor T(x, ly) = S(lx, Root) xor S(x, Root)

T(lx, ly) xor T(x, ly) = T(lx, x)

T(x, ly) = T(lx, ly) xor T(lx, x)

我们维护的是每个点是否在当前路径上,那么我们只需要将 T(lx, x) 上的点的状态改变,就实现了这个转移。

从 T(x, ly) 到 T(x, y) 同理。

实现了这个转移之后,我们就得到了 T(x, y) ,相比 S(x, y) 我们还需要将 LCA(x, y) 的状态改变,记录答案之后要再把 LCA 的状态改回去。因为我们需要维护的是 T(x, y)。

顺便说一下,使用的对树分块的方法,是 王室联邦 那道题的分块方法,维护一个栈。

目前在这道题的 Status 里的排名挨着 WJMZBMR 好开心~

46 930837 TomRiddle 23684 KB 80647 MS C++ 4776 B 2015-04-13 14:38:31
47 348468 WJMZBMR 12940 KB 80682 MS C++ 4383 B 2013-02-12 15:57:06

代码

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>using namespace std;inline void Read(int &Num)
{char c = getchar();bool Neg = false;while (c < '0' || c > '9') {if (c == '-') Neg = true;c = getchar();}Num = c - '0'; c = getchar();while (c >= '0' && c <= '9'){Num = Num * 10 + c - '0';c = getchar();}if (Neg) Num = -Num;
}typedef long long LL;const int MaxN = 100000 + 5, MaxQ = 100000 + 5;int n, m, q, BlkSize, Top, Index, ID_Index, Chg_Index, Qt;
int V[MaxN], W[MaxN], Col[MaxN], Father[MaxN], ID[MaxN], Depth[MaxN], S[MaxN], Cnt[MaxN], Jump[MaxN][20], Ti[MaxN];LL Ans;
LL AnsA[MaxQ];bool InPath[MaxN];struct Edge
{int v;Edge *Next;
} E[MaxN * 2], *P = E, *Point[MaxN];inline void AddEdge(int x, int y)
{++P; P -> v = y;P -> Next = Point[x]; Point[x] = P;
}void DFS(int x, int Fa, int Dep)
{Father[x] = Fa; Depth[x] = Dep;int Bottom = Top;for (Edge *j = Point[x]; j; j = j -> Next){if (j -> v == Fa) continue;DFS(j -> v, x, Dep + 1);if (Top - Bottom >= BlkSize){++ID_Index;while (Top > Bottom)ID[S[Top--]] = ID_Index;}}S[++Top] = x;
}struct Query
{int x, y, vx, vy, tl, Idx;
} Q[MaxQ];inline bool Cmp(Query q1, Query q2)
{if (q1.vx != q2.vx) return q1.vx < q2.vx;if (q1.vy != q2.vy) return q1.vy < q2.vy;return q1.tl < q2.tl;
}struct Chg
{int Pos, Num, Prev;
} C[MaxQ];inline void ChangeCol(int Num, int f)
{if (f == -1){    Ans -= (LL)V[Num] * (LL)W[Cnt[Num]];--Cnt[Num];}else{++Cnt[Num];Ans += (LL)V[Num] * (LL)W[Cnt[Num]];}
}void ChangeTL(int x, int y)
{if (x == y) return;if (x < y) {for (int i = x + 1; i <= y; ++i){if (InPath[C[i].Pos]){ChangeCol(Col[C[i].Pos], -1);ChangeCol(C[i].Num, 1);}Col[C[i].Pos] = C[i].Num;}}else{for (int i = x; i > y; --i){if (InPath[C[i].Pos]){ChangeCol(Col[C[i].Pos], -1);ChangeCol(C[i].Prev, 1);}Col[C[i].Pos] = C[i].Prev;}}
}inline void Reverse(int x)
{if (InPath[x]) {InPath[x] = false;ChangeCol(Col[x], -1);}else {InPath[x] = true;ChangeCol(Col[x], 1);}
}void Change(int x, int y)
{while (x != y){if (Depth[x] < Depth[y]) swap(x, y);Reverse(x); x = Father[x];     }
}int LCA(int x, int y)
{if (Depth[x] < Depth[y]) swap(x, y);int Dif = Depth[x] - Depth[y];for (int i = 0; i <= 18; ++i)if (Dif & (1 << i)) x = Jump[x][i];if (x == y) return x;for (int i = 18; i >= 0; --i)if (Jump[x][i] != Jump[y][i]){x = Jump[x][i];y = Jump[y][i];}return Father[x];
}void Prepare()
{for (int i = 1; i <= n; ++i) Jump[i][0] = Father[i];for (int j = 1; j <= 18; ++j)for (int i = 1; i <= n; ++i)Jump[i][j] = Jump[Jump[i][j - 1]][j - 1];
}int main()
{Read(n); Read(m); Read(q);for (int i = 1; i <= m; ++i) Read(V[i]);for (int i = 1; i <= n; ++i) Read(W[i]);int a, b;for (int i = 1; i <= n - 1; ++i) {Read(a); Read(b);AddEdge(a, b);AddEdge(b, a);}for (int i = 1; i <= n; ++i) Read(Col[i]);BlkSize = (int)pow(n, 0.667);DFS(1, 0, 0);while (Top > 0) ID[S[Top--]] = ID_Index;Prepare();for (int i = 1; i <= n; ++i) Ti[i] = Col[i];int f;for (int i = 1; i <= q; ++i){Read(f); Read(a); Read(b);if (f == 0){++Chg_Index;C[Chg_Index].Prev = Ti[a];Ti[a] = b;C[Chg_Index].Pos = a;C[Chg_Index].Num = b;}else{++Qt;Q[Qt].x = a; Q[Qt].y = b;Q[Qt].vx = ID[a]; Q[Qt].vy = ID[b];Q[Qt].tl = Chg_Index;Q[Qt].Idx = Qt;}}sort(Q + 1, Q + Qt + 1, Cmp);Ans = 0ll;ChangeTL(0, Q[1].tl);Change(Q[1].x, Q[1].y);int t = LCA(Q[1].x, Q[1].y);Reverse(t);   AnsA[Q[1].Idx] = Ans;  Reverse(t);for (int i = 2; i <= Qt; ++i){ChangeTL(Q[i - 1].tl, Q[i].tl);Change(Q[i - 1].x, Q[i].x);Change(Q[i - 1].y, Q[i].y);t = LCA(Q[i].x, Q[i].y);Reverse(t);AnsA[Q[i].Idx] = Ans; Reverse(t);}for (int i = 1; i <= Qt; ++i) printf("%lld\n", AnsA[i]);return 0;
}

  

转载于:https://www.cnblogs.com/JoeFan/p/4422201.html

[BZOJ 3052] [wc2013] 糖果公园 【树上莫队】相关推荐

  1. BZOJ.3052.[WC2013]糖果公园(树上莫队 带修改莫队)

    题目链接 BZOJ 当然哪都能交(都比在BZOJ交好),比如UOJ #58 //67376kb 27280ms //树上莫队+带修改莫队 模板题 #include <cmath> #inc ...

  2. 【WC2013】糖果公园 树上莫队

    树上莫队,将树分块,以x,y为一二关键字,以时间为第三关键字.暴力修改. #include <iostream> #include <cstdio> #include < ...

  3. 【BZOJ】3052: [wc2013]糖果公园 树分块+带修改莫队算法

    [题目]#58. [WC2013]糖果公园 [题意]给定n个点的树,m种糖果,每个点有糖果ci.给定n个数wi和m个数vi,第i颗糖果第j次品尝的价值是v(i)*w(j).q次询问一条链上每个点价值的 ...

  4. bzoj 4129 Haruna’s Breakfast 树上莫队

    按照dfs序分块,莫队乱搞 再套个权值分块 #include<cstdio> #include<iostream> #include<cstring> #inclu ...

  5. [学习笔记]树上莫队

    其实树上莫队是一个欧拉序而已嘛,像普通的莫队,特判一下出现过两次的值就行了 设 \(st_i\) 为 \(i\) 进栈的时间,\(ed_i\) 为 \(i\) 出栈的时间,\(dfn_x<dfn ...

  6. LG P4074 [WC2013] 糖果公园(带修莫队,树上莫队)

    LG P4074 [WC2013] 糖果公园 Solution 树上带修莫队,主要还是复习带修莫队和树上莫队. 带修莫队: 带修莫队要先对lll分块的序号作为第一关键字,对rrr分块的序号作为第二关键 ...

  7. uoj#58./bzoj3052 【WC2013】糖果公园 //树上带修改莫队

    uoj#58. [WC2013]糖果公园 题意 有一棵N(<=1e5)个点的树,每个点对应M(<=1e5)种糖果中的一种. 一条路径的权值定义为∑i(Vi∗∑tij=1Wj)\sum_i ...

  8. YBTOJ洛谷P4074:糖果公园(树上莫队)

    文章目录 解析 update: 代码 所谓树上莫队,就是在树上的莫队 (逃) 传送门 解析 似乎就是树上的这道题 考虑如何转化为序列问题呢? 考虑dfs序 但是又一个问题... 似乎这条链的dfs序不 ...

  9. 莫队算法(普通莫队、带修莫队、树上莫队、不删除莫队)学习笔记【理解+套路/核心代码+例题及题解】

    一.理解 我的理解就是巧妙的暴力,利用双指针以及分块思想,巧妙的移动双指针,时间复杂度可以达到O(NlogN). 强推博客:写的又好又全.链接 二.套路 1.普通莫队 [1]核心代码 bool cmp ...

  10. 莫队算法 (普通莫队、带修莫队、树上莫队)

    莫队算法 主要基于分块的思想 用结构体记录询问的左右端点及询问编号 (这是一个离线算法) 通过排序优化指针扫描顺序优化时间复杂度 . 1.普通莫队 例题:SP3267 DQUERY - D-query ...

最新文章

  1. 金蝶K/3 BOS产品培训教案
  2. OpenCL与异构并行计算
  3. Retrofit解析网页Json数据简单实例
  4. java post 登陆_java HttpPost 密码登录和提交表单的案例
  5. 小程序返回上一页并传参
  6. 新手入坑 java的开发语言环境
  7. 织梦5.7 10万新闻文章 生成测试
  8. Eclipse开发环境下,部署和配置svn的整个过程
  9. linux维护盘ISO,MYISO XPPE+Win10PE+porteus系统维护盘ISO量产全能版
  10. 谷歌翻译软件-免费谷歌翻译
  11. indexOf用法小结
  12. 网课作业答案在哪找?手把手教你查大学网课作业答案~
  13. 目前流行的数据分析软件有哪些?
  14. 交换机下配置banner login是做什么的
  15. 从0到1一个文件,用Python 实现 Web 框架
  16. 关闭rabbitmq连接健康检查
  17. Activiti核心API
  18. Tensorflow学习笔记——tf.set_random_seed函数
  19. windows sql server 如何卸载干净?
  20. 英语不好计算机好学吗,英语很差能学计算机专业吗

热门文章

  1. ipython notebook使用教程
  2. hyperparameter_hunter 超参数优化模块实践
  3. 学计算机用多大的u盘合适,u盘装系统需要多大的u盘|装系统需要多大的U盘
  4. 计算机语言疾病矫治操作流程,言语矫治专家决策系统的构建.doc
  5. 树莓派python蓝牙_怎样通过蓝牙仅使用Android手机为树莓派配置Wi-Fi网络
  6. 以太坊 solidity 函数修饰符总结 public、private、internal、external、view、pure的区别
  7. 微信小程序云开发教程-WXML入门-条件渲染
  8. python 读取网页并分词
  9. jquery ajax修改密码,提交form表单---修改密码 ajax、jQuery
  10. mysql更改安装路径命令_如何修改mysql的安装路径