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. PHP 网站隔离配置

    PHP网站间隔离 网站内目录与目录之间是可以访问的,在某些特定情况下这样是不安全的,如果目录间网址权限被黑客利用很可能造成数据流失,在这里我们可以通过PHPopen_basedir来实现网站间目录隔离 ...

  2. [翻译]在gulp构建工具中使用PostCSS

    前言 PostCSS已经在一段时间内迅速普及,如果你还不知道PostCSS或还没有使用它,我建议你看一下之前的一篇介绍文章<PostCSS简介>,其中介绍了使用PostCSS的基本方法,包 ...

  3. APIGateway网关安全设计

    Spring Cloud里面有个组件 Zuul网关 网关和 过滤器 拦截器很相似 网关可以实现过滤器 拦截器的功能 而且可以实现Nginx的基本功能 反向代理 负载均衡ribbon Nginx是软负载 ...

  4. java如何调用接口

    其实对于java调用接口进行获取对方服务器的数据在开发中特别常见,然而一些常用的基础的知识总是掌握不牢,让人容易忘记,写下来闲的时候看看,比回想总会好一些. 总体而言,一些东西知识点一直复制粘贴容易依 ...

  5. LeetCode—-Sort List

    LeetCode--Sort List Question Sort a linked list in O(n log n) time using constant space complexity. ...

  6. JS复制内容到剪贴板: 兼容IE、Firefox、Chrome、Safari所有浏览器【转】

    正 文: 现在浏览器种类也越来越多,诸如 IE.Firefox.Chrome.Safari等等,因此现在要实现一个js复制内容到剪贴板的小功能就不是一件那么容易的事了. 在FLASH 9 时代,有一个 ...

  7. 解决com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Specified key was too long; max key length is 767 bytes异常

    错误截图: 解决方法: 用root进入mysql终端,执行以下命令: alter database hive character set latin1;

  8. sqoop数据导入到Hdfs 或者hive

    用java代码调用shell脚本执行sqoop将hive表中数据导出到mysql http://www.cnblogs.com/xuyou551/p/7999773.html 用sqoop将mysql ...

  9. Spring -- aop, 用Aspectj进行AOP开发

    1. 概要 添加类库:aspectjrt.jar和aspectjweaver.jar 添加aop schema. 定义xml元素:<aop:aspectj-autoproxy> 编写jav ...

  10. Json -- 语法和示例,javascript 解析Json

    1. 语法 JSON(JavaScriptObject Notation)一种简单的数据格式,比xml更轻巧.JSON是JavaScript原生格式,这意味着在JavaScript中处理JSON数据不 ...