Written with StackEdit.

Description

\(Candyland\) 有一座糖果公园,公园里不仅有美丽的风景、好玩的游乐项目,还有许多免费糖果的发放点,这引来了许多贪吃的小朋友来糖果公园游玩。

糖果公园的结构十分奇特,它由 \(n\) 个游览点构成,每个游览点都有一个糖果发放处,我们可以依次将游览点编号为 \(1\) 至 \(n\)。有 \(n – 1\) 条双向道路连接着这些游览点,并且整个糖果公园都是连通的,即从任何一个游览点出发都可以通过这些道路到达公园里的所有其它游览点。

糖果公园所发放的糖果种类非常丰富,总共有 \(m\) 种,它们的编号依次为 \(1\) 至 \(m\)。每一个糖果发放处都只发放某种特定的糖果,我们用 \(C_i\)​ 来表示 \(i\) 号游览点的糖果。

来到公园里游玩的游客都不喜欢走回头路,他们总是从某个特定的游览点出发前往另一个特定的游览点,并游览途中的景点,这条路线一定是唯一的。他们经过每个游览点,都可以品尝到一颗对应种类的糖果。

大家对不同类型糖果的喜爱程度都不尽相同。 根据游客们的反馈打分,我们得到了糖果的美味指数, 第 \(i\) 种糖果的美味指数为 \(V_i\)​。另外,如果一位游客反复地品尝同一种类的糖果,他肯定会觉得有一些腻。根据量化统计,我们得到了游客第 \(i\) 次品尝某类糖果的新奇指数 \(W_i\)​。如果一位游客第 \(i\) 次品尝第 \(j\) 种糖果,那么他的愉悦指数 \(H\)将会增加对应的美味指数与新奇指数的乘积,即 \(V_j​×W_i\)​。这位游客游览公园的愉悦指数最终将是这些乘积的和。

当然,公园中每个糖果发放点所发放的糖果种类不一定是一成不变的。有时,一些糖果点所发放的糖果种类可能会更改(也只会是 \(m\) 种中的一种),这样的目的是能够让游客们总是感受到惊喜。

糖果公园的工作人员小 \(A\) 接到了一个任务,那就是根据公园最近的数据统计出每位游客游玩公园的愉悦指数。但数学不好的小 \(A\) 一看到密密麻麻的数字就觉得头晕,作为小 \(A\) 最好的朋友,你决定帮他一把。

Input

第一行包含三个正整数 \(n\), \(m\), \(q\), 分别表示游览点个数、 糖果种类数和操作次数。

第二行包含 \(m\) 个正整数 \(V_1, V_2​, …, V_m\)​。

第三行包含 \(n\) 个正整数 \(W_1​, W_2​, …, W_n\)​。

第四行到第 \(n + 2\) 行,每行包含两个正整数 \(A_i\)​, \(B_i\)​,表示这两个游览点之间有路径可以直接到达。

第 \(n + 3\) 行包含 \(n\) 个正整数 \(C_1, C_2​, …, C_n\)。

接下来 \(q\) 行, 每行包含三个整数 \(Type, x, y\),表示一次操作:

若 \(Type\) 为 \(0\),则 \(1 ≤ x ≤ n\), \(1 ≤ y ≤ m\),表示将编号为 \(x\) 的游览点发放的糖果类型改为 \(y\);

若 \(Type\) 为 \(1\),则 \(1 ≤ x,y ≤ n\),表示对出发点为 \(x\),终止点为 \(y\) 的路线询问愉悦指数。

Output

按照输入的先后顺序,对于每个 \(Type\) 为 \(1\) 的操作输出一行,用一个正整数表示答案。

Solution

  • 树上带修莫队板子题.
  • 树上分块使用王室联邦的分块,能保证每块大小在\([B,3B]\)内.
  • 移动时,若从\((pu,pv)\)移动到\((u,v)\),则只需对路径\((pu,u),(pv,v)\)的点是否包含情况取反,\(LCA\)不处理,保存答案前对\((u,v)\)的\(LCA\)取反,答案保存后再将这个点取反回去.
  • 正确性?我也不会证.大概可以参照VFleaKingdalao的blog.
#include<bits/stdc++.h>
using namespace std;
typedef long long LoveLive;
inline LoveLive read()
{
LoveLive out=0,fh=1;
char jp=getchar();
while ((jp>'9'||jp<'0')&&jp!='-')
jp=getchar();
if (jp=='-')
{
fh=-1;
jp=getchar();
}
while (jp>='0'&&jp<='9')
{
out=out*10+jp-'0';
jp=getchar();
}
return out*fh;
}
const int MAXT=17;
const int MAXN=1e5+10;
int ecnt=0,head[MAXN];
int nx[MAXN<<1],to[MAXN<<1];
inline void addedge(int u,int v)
{
++ecnt;
nx[ecnt]=head[u];
to[ecnt]=v;
head[u]=ecnt;
}
inline void ins(int u,int v)
{
addedge(u,v);
addedge(v,u);
}
int n,m,Q;
int cntQ=0,cntC=0;
LoveLive Ans[MAXN];
int belong[MAXN],cntB=0;
struct Query{
int u,v;
int id,tim;
bool operator < (const Query &rhs) const
{
if(belong[u]!=belong[rhs.u])
return belong[u]<belong[rhs.u];
if(belong[v]!=belong[rhs.v])
return belong[v]<belong[rhs.v];
return tim<rhs.tim;
}
}q[MAXN];
int stk[MAXN],top=0,BlockSize;
int fa[MAXN],dep[MAXN];
void dfs(int u,int Fa)
{
fa[u]=Fa;
dep[u]=dep[Fa]+1;
int bot=top;
for(int i=head[u];i;i=nx[i])
{
int v=to[i];
if(v!=Fa)
{
dfs(v,u);
if(top-bot>=BlockSize)
{
++cntB;
for(;top!=bot;--top)
belong[stk[top]]=cntB;
}
}
}
stk[++top]=u;
}
void BuildBlocks()
{
dfs(1,0);
for(;top;--top)
belong[stk[top]]=cntB;
}
int up[MAXN][MAXT+1];
void init_lca()
{
for(int i=1;i<=n;++i)
up[i][0]=fa[i];
for(int j=1;j<=MAXT;++j)
for(int i=1;i<=n;++i)
up[i][j]=up[up[i][j-1]][j-1];
}
int query_lca(int a,int b)
{
if(a==b)
return a;
if(dep[a]>dep[b])swap(a,b);
int dl=dep[b]-dep[a];
for(int i=0;i<=MAXT && (1<<i)<=dl;i++)
if(dl&(1<<i))
b=up[b][i];
if(a==b)return a;
for(int i=MAXT;i>=0;--i)
{
if(up[a][i]!=up[b][i])
{
a=up[a][i];
b=up[b][i];
}
}
return up[b][0];
}
int newx[MAXN],pos[MAXN],tim[MAXN];//存储修改操作的信息
LoveLive val[MAXN],w[MAXN];
int col[MAXN];
LoveLive res;
int pu,pv,cnt[MAXN];//记录当前的路径和答案
int cur;//当前时间
int vis[MAXN];
void reverse(int u)//将u在路径上的情况取反
{
if(vis[u])
{
res-=val[col[u]]*w[cnt[col[u]]];
--cnt[col[u]];
}
else
{
++cnt[col[u]];
res+=val[col[u]]*w[cnt[col[u]]];
}
vis[u]^=1;
}
void move(int u,int v)//路径端点从u移到v 不考虑lca
{
int LCA=query_lca(u,v);
while(u!=LCA)
reverse(u),u=fa[u];
while(v!=LCA)
reverse(v),v=fa[v];
}
int pre[MAXN];//此次操作前,被操作的点本来的颜色
void travel_ahead()//从cur-1转移到cur,执行cur的修改
{
int flag=0;
if(vis[pos[cur]])
flag=1,reverse(pos[cur]);//颜色变化了,需要重新计算贡献,移出修改颜色后再移回来
pre[cur]=col[pos[cur]];
col[pos[cur]]=newx[cur];
if(flag)
reverse(pos[cur]);
}
void travel_back()//从cur+1转移到cur,撤销cur的修改
{
int flag=0;
if(vis[pos[cur]])
flag=1,reverse(pos[cur]);
col[pos[cur]]=pre[cur];
if(flag)
reverse(pos[cur]);
}
void time_travel(int tar)
{
while(cur<cntC && tim[cur+1]<=tar)
++cur,travel_ahead();
while(cur && tim[cur]>tar)
travel_back(),--cur;
}
int main()
{
n=read(),m=read(),Q=read();
BlockSize=pow(n,0.666666666);
for(int i=1;i<=m;++i)
val[i]=read();
for(int i=1;i<=n;++i)
w[i]=read();
for(int i=1;i<n;++i)
{
int u=read(),v=read();
ins(u,v);
}
for(int i=1;i<=n;++i)
col[i]=read();
BuildBlocks();
init_lca();
for(int i=1;i<=Q;++i)
{
int op=read();
assert(op==0 || op==1);
if(op==1)
{
++cntQ;
q[cntQ].u=read();
q[cntQ].v=read();
q[cntQ].id=cntQ;
q[cntQ].tim=i;
}
else if(op==0)
{
++cntC;
pos[cntC]=read();
newx[cntC]=read();
tim[cntC]=i;
}
}
sort(q+1,q+cntQ+1);
// cerr<<"sorted"<<endl;
pu=pv=1;
for(int i=1;i<=cntQ;++i)
{
time_travel(q[i].tim);
// cerr<<"traveled"<<endl;
move(pu,q[i].u);
pu=q[i].u;
move(pv,q[i].v);
pv=q[i].v;
int LCA=query_lca(pu,pv);
reverse(LCA);
Ans[q[i].id]=res;
reverse(LCA);
}
for(int i=1;i<=cntQ;++i)
printf("%lld\n",Ans[i]);
return 0;
}

bzoj 3052 糖果公园的更多相关文章

  1. 【BZOJ】【3052】【WC2013】糖果公园

    树分块 老早(大约一个月以前?)就听说这道神题了……orz rausen 一直拖到现在才做……发现还是不会呢= = 只好也去Orz了Hzwer和zky http://hzwer.com/5250.ht ...

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

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

  3. [BZOJ 3052] [wc2013] 糖果公园 【树上莫队】

    题目链接:BZOJ - 3052 题目分析 这道题就是非常经典的树上莫队了,并且是带修改的莫队. 带修改的莫队:将询问按照 左端点所在的块编号为第一关键字,右端点所在的块为第二关键字,位于第几次修改之 ...

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

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

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

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

  6. 【WC2013】糖果公园

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

  7. UOJ #58 【WC2013】 糖果公园

    题目链接:糖果公园 听说这是一道树上莫队的入门题,于是我就去写了--顺便复习了一下莫队的各种姿势. 首先,我们要在树上使用莫队,那么就需要像序列一样给树分块.这个分块的过程就是王室联邦这道题(vfle ...

  8. UOJ58 【WC2013】糖果公园

    本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/ ...

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

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

随机推荐

  1. .NET计时器的使用-Stopwatch类

    作用: 微软提供的常用于统计时间消耗的类,作为一个固定的API接口供大家使用. 先看代码: using System; using System.Collections.Generic; using ...

  2. 实验一 Linux初步认识

    遇到的困难和心得体会: 1.在操作过程中,有道作业是建立一个opt/forloutest的文件,而我建立了一个 OPT文件,cd OPT,却显示not a directory,通过阅读<linu ...

  3. [Android]android Service后台防杀

    网上有很多办法,方法一:在JNI里面fork出子进程service在单独的进程中,在service中调用JNI的代码,然后fork出一个进程,然后让我们的service进程和fork出来的子进程一直运 ...

  4. UNIDAC的安装

    UNIDAC的安装1.在source目录中找到对应Delphi版本目录的make.bat文件,修改其中的 set IdeDir="D:\Application\DelphiXE2指到你的de ...

  5. hibernate的多对多配置

    Teacher.java package com.xiaostudy.domain; import java.util.HashSet; import java.util.Set; /** * Tea ...

  6. Logstash过滤器修改数据

    数据修改(Mutate) filters/mutate 插件是 Logstash 另一个重要插件.它提供了丰富的基础类型数据处理能力.包括类型转换,字符串处理和字段处理等. 类型转换 类型转换是 fi ...

  7. scala学习手记19 - Option类型

    看到Option类型就知道这本教材应该要说那个了. 使用过guava后,应该知道guava中的Optional类的作用是什么.算了找下原始文档好了: Optional<T> is a wa ...

  8. srm开发(基于ssh)(4)

    1 input处理内容补充 -在struts2里面有错误处理机制,当上传文件超过默认的大小,自动返回结果input -在struts.xml中配置input的返回结果 <!-- 配置input结 ...

  9. js进阶---12-12、jquery事件委托怎么使用

    js进阶---12-12.jquery事件委托怎么使用 一.总结 一句话总结:通过on方法(事件委托),给要绑定事件的元素的祖先绑定事件,从而达到效果. 1.事件委托是什么? 通过事件冒泡,让子元素绑 ...

  10. spring3: AOP 之 通知顺序

    如果我们有多个通知想要在同一连接点执行,那执行顺序如何确定呢?Spring AOP使用AspectJ的优先级规则来确定通知执行顺序.总共有两种情况:同一切面中通知执行顺序.不同切面中的通知执行顺序. ...