题目链接: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;
}

  

[BZOJ 3052] [wc2013] 糖果公园 【树上莫队】的更多相关文章

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

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

  2. BZOJ 3052: [wc2013]糖果公园 | 树上莫队

    题目: UOJ也能评测 题解 请看代码 #include<cstdio> #include<algorithm> #include<cstring> #includ ...

  3. 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 ...

  4. P4074 [WC2013]糖果公园 树上莫队带修改

    题目链接 Candyland 有一座糖果公园,公园里不仅有美丽的风景.好玩的游乐项目,还有许多免费糖果的发放点,这引来了许多贪吃的小朋友来糖果公园游玩. 糖果公园的结构十分奇特,它由 nn 个游览点构 ...

  5. bzoj 3052: [wc2013]糖果公园 带修改莫队

    3052: [wc2013]糖果公园 Time Limit: 250 Sec  Memory Limit: 512 MBSubmit: 506  Solved: 189[Submit][Status] ...

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

    问题描述 Candyland 有一座糖果公园,公园里不仅有美丽的风景.好玩的游乐项目,还有许多免费糖果的发放点,这引来了许多贪吃的小朋友来糖果公园游玩.糖果公园的结构十分奇特,它由 n 个游览点构成, ...

  7. 【WC2013】糖果公园 [树上莫队]

    题意: 一棵树,修改一个点的颜色,询问两点路径上每种颜色的权值$val[c]$*出现次数的权值$cou[w[c]]$的和 sro VFK 树上莫队 按照王室联邦的方法分块,块的大小直径个数有保证,并不 ...

  8. 洛谷P4074 [WC2013]糖果公园(莫队)

    传送门 总算会树形莫队了…… 上次听说树形莫队是给树分块,实在看不懂.然后用括号序列的方法做总算能弄明白了 先说一下什么是括号序列,就是在$dfs$的时候,进入的时候记录一下,出去的时候也记录一下 拿 ...

  9. bzoj 3052: [wc2013]糖果公园【树上带修改莫队】

    参考:http://blog.csdn.net/lych_cys/article/details/50845832 把树变成dfs括号序的形式,注意这个是不包含lca的(除非lca是两点中的一个) 然 ...

随机推荐

  1. linux-0.11内核 调试教程+GCC源代码

    http://pan.baidu.com/share/home?uk=453348606&view=share#category/type=0 http://blog.csdn.net/old ...

  2. delegate和event

    经过查阅资料和自己的理解整理出来的,欢迎大家指教. delegate和event 何时使用: 异步的时候,比如加载完成通知. 需要回调的时候,比如按钮点击.动画播放结束等. 发送事件通知的时候. 比如 ...

  3. Windows下Memcached在.Net程序中的实际运用(从Memcached客户端Enyim的库的编译到实际项目运用)

    1.一点基础概念 2.获取EnyimMemcached客户端的源代码并编译出动态库 3.Memcached的服务器安装(windows server) 4.在web项目中实战 一.基础概念 memca ...

  4. Js 直接下载保存文件

    //直接下载保存文件 function Download(filePath) { // 如果中间IFRAME不存在,则添加 if (!document.getElementById("_SA ...

  5. ionic 项目分享【转】No.3

    写在文章前:由于最近研究ionic框架,深感这块的Demo寥寥可数,而大家又都藏私,堂堂天朝,何时才有百家争鸣之象,开源精神吾辈当仁不让! 原文地址暂时忘记了 ,如果有知道的麻烦在评论处帮忙说一下 , ...

  6. Java-struts2 通过MODEL接收表单数据的方法

    接收数据的时候经常会出问题: 1.记住action = “”到的路径,最好用全路径 <a href="../Struts/user/hello?user.name=xxzzzzzzzz ...

  7. [DEncrypt] MySecurity--安全加密/Base64/文件加密 (转载)

    点击下载 MySecurity.zip 这个类是关于加密,解密的操作,文件的一些高级操作1.MySecurity  加密字符串2.MySecurity  加密字符串 密钥为系统默认 012345678 ...

  8. Analyze 静态分析工具中显示 大量的CF类型指针 内存leak 问题, Core Foundation 类型指针内存泄漏

    Analyze 静态分析工具中显示 大量的CF类型指针 内存leak 问题   今天使用Analyze 看了下项目,   解决办法,项目中使用了ARC,OC的指针类型我们完全不考虑release的问题 ...

  9. 如何写类库方法、属性等的注释,才能在其他地方调用dll文件时,在代码里出现智能提示?

    我的本意是想整理下以往写过的代码库,给自己的代码增加复用性.一段时间后,可能自己对写过的代码是什么含义会忘掉,或者别人看自己的代码, 增加可懂性的考虑,决定要添加注释.(好像语句不通:)可是发现,在其 ...

  10. C++专题 - 面向对象总结

    1.         什么是类?什么是对象?对象与类的关系是什么? 答:类就是相同的数据和相同的一组对象的集合,即类是对具有相同数据结构和相同操作的一类对象的描述: 对象是描述其属性的数据以及对这些数 ...