http://uoj.ac/problem/58

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]糖果公园——题解的更多相关文章

  1. 【BZOJ3052】[wc2013]糖果公园 带修改的树上莫队

    [BZOJ3052][wc2013]糖果公园 Description Input Output Sample Input Sample Input Sample Output 84 131 27 84 ...

  2. ●UOJ58 [WC2013]糖果公园

    题链: http://uoj.ac/problem/58题解: 树上带修莫队. 每个块的大小为$n^{\frac{2}{3}}$,在dfs时,把点集分为若干块. 然后类似序列带修莫队,三个关键字:be ...

  3. 【bzoj3052】[wc2013]糖果公园 带修改树上莫队

    题目描述 给出一棵n个点的树,每个点有一个点权,点权范围为1~m.支持两种操作:(1)修改一个点的点权 (2)对于一条路径,求$\sum\limits_{i=1}^m\sum\limits_{j=1} ...

  4. BZOJ3052:[WC2013]糖果公园

    浅谈莫队:https://www.cnblogs.com/AKMer/p/10374756.html 题目传送门:https://lydsy.com/JudgeOnline/problem.php?i ...

  5. 【BZOJ3052&UOJ58】糖果公园(树上带修莫队)

    题意:给定一个n个点的树,每个结点上有一种颜色c[i] 定义一条简单路径的偷税指数为simga (sigma w[i](i=0..a[j]))*v[j](j=0..m),其中a[i]为第i种颜色在路径 ...

  6. [BZOJ3052][UOJ#58][WC2013]糖果公园

    [BZOJ3052][UOJ#58][WC2013]糖果公园 试题描述 Candyland 有一座糖果公园,公园里不仅有美丽的风景.好玩的游乐项目,还有许多免费糖果的发放点,这引来了许多贪吃的小朋友来 ...

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

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

  8. 洛谷 P4074 [WC2013]糖果公园 解题报告

    P4074 [WC2013]糖果公园 糖果公园 树上待修莫队 注意一个思想,dfn序处理链的方法,必须可以根据类似异或的东西,然后根据lca分两种情况讨论 注意细节 Code: #include &l ...

  9. AC日记——[WC2013]糖果公园 cogs 1817

    [WC2013]糖果公园 思路: 带修改树上莫队(模板): 来,上代码: #include <cmath> #include <cstdio> #include <cst ...

随机推荐

  1. 372. Delete Node in a Linked List【LintCode java】

    Description Implement an algorithm to delete a node in the middle of a singly linked list, given onl ...

  2. mac os x下应用endnote异常解决办法

    最近在用Office+Endnote写论文,使用拼音输入法换字时会出现重字和拼音的情况,比如我想打“桥连”,最终出现的是"qiao'lian桥lian桥连”.后来发现这个问题时由endnot ...

  3. [LeetCode] 53. Maximum Subarray 解题思路

    Find the contiguous subarray within an array (containing at least one number) which has the largest ...

  4. addeventlistener和attachevent

    区别: 1.ie8及以下版本前者无效,只能使用后者: 2,关于第三个参数,如果是true则捕获状态触发,为false;则为冒泡状态触发 何为冒泡,何为捕获? 这就好比捕鱼,冒泡吗,鱼向上吐泡泡,所以当 ...

  5. LintCode-174.删除链表中倒数第n个节点

    删除链表中倒数第n个节点 给定一个链表,删除链表中倒数第n个节点,返回链表的头节点. 注意事项 链表中的节点个数大于等于n 样例 给出链表 1->2->3->4->5-> ...

  6. 2-c语言作业1

    #include<stdio.h> #include<math.h> int main(void) { int money,year; double rate,sun; pri ...

  7. QWidget一生,从创建到销毁事件流

    版权声明:若无来源注明,Techie亮博客文章均为原创. 转载请以链接形式标明本文标题和地址: 本文标题:QWidget一生,从创建到销毁事件流     本文地址:http://techieliang ...

  8. animate.css与wow.js制作网站动效

    animate.css 官网:https://daneden.github.io/animate.css/ 包括:attention seekers:关注者 bouncing entrances:跳跃 ...

  9. 图像检测算法Halcon 10的使用

    安装完成HALCON之后,在VS项目中添加动态链接库配置项目,并修改此项目属性的包含目录.库目录和链接器.

  10. [CLR via C#]引用类型和值类型

    一.引用类型与值类型的区别 CLR支持两种类型:引用类型和值类型.引用类型总是从托管堆上分配的,C#的new操作符会返回对象的内存地址.使用引用类型时,必须注意到一些性能问题. 1)内存必须从托管堆上 ...