BZOJ3052 & UOJ58:[WC2013]糖果公园——题解
http://www.lydsy.com/JudgeOnline/problem.php?id=3052

输入格式

输出格式

input
4 3 5
1 9 2
7 6 5 1
2 3
3 1
3 4
1 2 3 2
1 1 2
1 4 2
0 2 1
1 1 2
1 4 2
output
84
131
27
84
——————————————————————————————————————
这题对于一个刚学莫队的人来说……挺萌的。
首先先对树分块,具体请看我的前一篇博客王室联邦我们就可以知道,假设我们要分块,我们设预期分块大小为s,则所有块的大小可为[s,3s]。
按照这种分块方法分块即可,注意为了我们算法的速度,分块大小s=n的2/3次方,证明可看小兔大佬的博客中单点修改莫队。
(dfs同时预处理LCA所需要的几个数据,以后会用)
在那之后按照莫队的思路为询问排序,然后开始我们正式的算法。
(排序时0号点的l和r都设成1(看到下面的操作之后就会知道这样做干什么了))
这里说一下个别几个数组的含义。
1.sta[i]:i是否在当前路径上,是为1.
2.last[i]:第i个操作为修改时,修改前的颜色。
3.cc[i]:最终i点的颜色。
4.col[i]:当前操作时i点的颜色。
再说一个函数rev(i)表示将i这个点在我们的路径上被添加/删除。
剩下的应该都能看得懂,我就不说什么了。
首先按照排序后顺序扫询问,我们得到了我们当前的询问和前一个询问。
那么首先我们需要将前一个询问的id和后一个询问的id中间的修改操作修改了。
然后就是最神奇的操作了,solve操作的证明详见vfk的博客。
(当然你也可以通过画图肉眼观察法证明,以下简述solve内部操作)
我们把当前的左询问节点l和之前的左询问节点l0之间的最短路取反。(当然同时对右节点也是一样)
然后取反左右询问节点的LCA,再更新cur,在取反LCA,这样我们就得到了这个询问的答案了。
#include<cstdio>
#include<stack>
#include<cctype>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=;
const int INF=;
inline ll read(){
ll X=,w=;char ch=;
while(!isdigit(ch)){w|=ch=='-';ch=getchar();}
while(isdigit(ch))X=(X<<)+(X<<)+(ch^),ch=getchar();
return w?-X:X;
}
struct node{
int to;
int nxt;
}edge[N*];
struct qu{
int id,l,r,bl,br;
}qry[N];
int n,m,Q,q,s,cnt,head[N];
int top,idx,stk[N],blk[N];
int anc[N][],dep[N];
int v[N],cc[N],col[N],sum[N];
int a[N],b[N],op[N],last[N];
ll cur,ans[N],w[N];
bool sta[N];
inline void add(int u,int v){
cnt++;
edge[cnt].to=v;
edge[cnt].nxt=head[u];
head[u]=cnt;
return;
}
bool cmp(qu d,qu e){
if(d.bl!=e.bl)return d.bl<e.bl;
if(d.br!=e.br)return d.br<e.br;
return d.id<e.id;
}
void dfs(int u){
int st=top;
dep[u]=dep[anc[u][]]+;
for(int i=head[u];i;i=edge[i].nxt){
int v=edge[i].to;
if(v==anc[u][])continue;
anc[v][]=u;
dfs(v);
if(top-st>=s){
idx++;
while(top>st)blk[stk[top--]]=idx;
}
}
stk[++top]=u;
return;
}
int LCA(int i,int j){
if(dep[i]<dep[j])swap(i,j);
for(int k=;k>=;k--){
if(dep[anc[i][k]]>=dep[j])i=anc[i][k];
}
if(i==j)return i;
for(int k=;k>=;k--){
if(anc[i][k]!=anc[j][k])i=anc[i][k],j=anc[j][k];
}
return anc[i][];
}
void init(){
n=read();m=read();Q=read();s=pow(n,2.0/3.0);
for(int i=;i<=m;i++)v[i]=read();
for(int i=;i<=n;i++)w[i]=read()+w[i-];
for(int i=;i<n;i++){
int u=read(),v=read();
add(u,v);add(v,u);
}
for(int i=;i<=n;i++)cc[i]=col[i]=read();
dfs();
while(top)blk[stk[top--]]=idx;
for(int j=;j<=;j++){
for(int i=;i<=n;i++){
anc[i][j]=anc[anc[i][j-]][j-];
}
}
return;
}
inline void rev(int x){
cur-=w[sum[col[x]]]*v[col[x]];
sta[x]?sum[col[x]]--:sum[col[x]]++;
sta[x]=!sta[x];
cur+=w[sum[col[x]]]*v[col[x]];
return;
}
inline void solve(int x,int y){
int l=LCA(x,y);
while(x!=l)rev(x),x=anc[x][];
while(y!=l)rev(y),y=anc[y][];
return;
}
inline void modify(int x,int y){
if(!sta[x]){
col[x]=y;
return;
}
rev(x);
col[x]=y;
rev(x);
return;
}
inline void upt(int tarT,int curT){
while(curT<tarT){
curT++;
if(!op[curT])modify(a[curT],b[curT]);
}
while(curT>tarT){
if(!op[curT])modify(a[curT],last[curT]);
curT--;
}
return;
}
int main(){
init();
for(int i=;i<=Q;i++){
op[i]=read(),a[i]=read(),b[i]=read();
if(op[i]){
qry[++q].id=i;
if(blk[a[i]]>blk[b[i]])swap(a[i],b[i]);
qry[q].l=a[i];qry[q].r=b[i];
qry[q].bl=blk[a[i]];qry[q].br=blk[b[i]];
}else last[i]=cc[a[i]],cc[a[i]]=b[i];
}
sort(qry+,qry+q+,cmp);
qry[].l=qry[].r=;
for(int i=;i<=q;i++){
upt(qry[i].id,qry[i-].id);
solve(qry[i].l,qry[i-].l);solve(qry[i].r,qry[i-].r);
int l=LCA(qry[i].l,qry[i].r);
rev(l);
ans[qry[i].id]=cur;
rev(l);
}
for(int i=;i<=Q;i++){
if(op[i])printf("%lld\n",ans[i]);
}
return ;
}
BZOJ3052 & UOJ58:[WC2013]糖果公园——题解的更多相关文章
- 【BZOJ3052】[wc2013]糖果公园 带修改的树上莫队
[BZOJ3052][wc2013]糖果公园 Description Input Output Sample Input Sample Input Sample Output 84 131 27 84 ...
- ●UOJ58 [WC2013]糖果公园
题链: http://uoj.ac/problem/58题解: 树上带修莫队. 每个块的大小为$n^{\frac{2}{3}}$,在dfs时,把点集分为若干块. 然后类似序列带修莫队,三个关键字:be ...
- 【bzoj3052】[wc2013]糖果公园 带修改树上莫队
题目描述 给出一棵n个点的树,每个点有一个点权,点权范围为1~m.支持两种操作:(1)修改一个点的点权 (2)对于一条路径,求$\sum\limits_{i=1}^m\sum\limits_{j=1} ...
- BZOJ3052:[WC2013]糖果公园
浅谈莫队:https://www.cnblogs.com/AKMer/p/10374756.html 题目传送门:https://lydsy.com/JudgeOnline/problem.php?i ...
- 【BZOJ3052&UOJ58】糖果公园(树上带修莫队)
题意:给定一个n个点的树,每个结点上有一种颜色c[i] 定义一条简单路径的偷税指数为simga (sigma w[i](i=0..a[j]))*v[j](j=0..m),其中a[i]为第i种颜色在路径 ...
- [BZOJ3052][UOJ#58][WC2013]糖果公园
[BZOJ3052][UOJ#58][WC2013]糖果公园 试题描述 Candyland 有一座糖果公园,公园里不仅有美丽的风景.好玩的游乐项目,还有许多免费糖果的发放点,这引来了许多贪吃的小朋友来 ...
- bzoj 3052: [wc2013]糖果公园 带修改莫队
3052: [wc2013]糖果公园 Time Limit: 250 Sec Memory Limit: 512 MBSubmit: 506 Solved: 189[Submit][Status] ...
- 洛谷 P4074 [WC2013]糖果公园 解题报告
P4074 [WC2013]糖果公园 糖果公园 树上待修莫队 注意一个思想,dfn序处理链的方法,必须可以根据类似异或的东西,然后根据lca分两种情况讨论 注意细节 Code: #include &l ...
- AC日记——[WC2013]糖果公园 cogs 1817
[WC2013]糖果公园 思路: 带修改树上莫队(模板): 来,上代码: #include <cmath> #include <cstdio> #include <cst ...
随机推荐
- spark history server
参考:http://blog.csdn.net/lsshlsw/article/details/44786575 为什么需要historyServer? 在运行Spark Application的时候 ...
- convert-Csharp-DateTime-Ticks-to-js
<!DOCTYPE html> <html> <head> <script> function myFunction() { var b = forma ...
- 敏捷开发学习笔记-Agile development(AM)
以人为核心,迭代,循序渐进 项目被切分为多个子项目,每个子项目都经过测试,具备集成和可运行的特征 5个价值观:沟通.简单.反馈.勇气.谦逊 敏捷模型与瀑布模型的区别 相对于瀑布模型,提高开发效率和 ...
- spark写入ES(动态模板)
使用es-hadoop插件,主要使用elasticsearch-spark-20_2.11-6.2.x.jar 官网:https://www.elastic.co/guide/en/elasticse ...
- 百度翻译api 实现简易微信翻译小程序
介绍 口袋翻译 口袋翻译 微信小程序 翻译功能 含7类语言的相互翻译 包含最近10条的翻译历史回溯功能 微信搜索:简e翻译 功能展示 使用百度翻译api需要申请 appid 与 key 并在 ap ...
- hadoop3.0新特性及新功能
Hadoop-3.0.0-alpha2版本发布,相比之前的hadoop-2.x有一系列的功能增强.但目前还是个alpha版本,有很多bug,且不能保证API的稳定和质量. 主要变化 Java最低版本要 ...
- solidity 智能合约操作
合约编译 #!/usr/bin/env python # coding: utf8 import json import os # Solc Compiler from functools impor ...
- Merkle Patricia Tree (MPT) 以太坊中的默克尔树
本篇博文是自己学习mpt的过程,边学边记录,很多原理性内容非自己原创,好的博文将会以链接形式进行共享. 一.什么是mpt MPT是以太坊中的merkle改进树,基于基数树,即前缀树改进而来,大大提高了 ...
- oracle常用函数总结
Oracle常用函数总结 ---oracle常用函数-----一.数值型常用函数----取整数--select floor(10.1) from dual;--将n四舍五入,保留小数点后m位(默认情况 ...
- [C++] OOP - Base and Derived Classes
There is a base class at the root of the hierarchy, from which the other class inherit, directly or ...