bzoj 3052 糖果公园
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 糖果公园的更多相关文章
- 【BZOJ】【3052】【WC2013】糖果公园
树分块 老早(大约一个月以前?)就听说这道神题了……orz rausen 一直拖到现在才做……发现还是不会呢= = 只好也去Orz了Hzwer和zky http://hzwer.com/5250.ht ...
- bzoj 3052: [wc2013]糖果公园 带修改莫队
3052: [wc2013]糖果公园 Time Limit: 250 Sec Memory Limit: 512 MBSubmit: 506 Solved: 189[Submit][Status] ...
- [BZOJ 3052] [wc2013] 糖果公园 【树上莫队】
题目链接:BZOJ - 3052 题目分析 这道题就是非常经典的树上莫队了,并且是带修改的莫队. 带修改的莫队:将询问按照 左端点所在的块编号为第一关键字,右端点所在的块为第二关键字,位于第几次修改之 ...
- 【BZOJ】3052: [wc2013]糖果公园 树分块+带修改莫队算法
[题目]#58. [WC2013]糖果公园 [题意]给定n个点的树,m种糖果,每个点有糖果ci.给定n个数wi和m个数vi,第i颗糖果第j次品尝的价值是v(i)*w(j).q次询问一条链上每个点价值的 ...
- 【BZOJ-3052】糖果公园 树上带修莫队算法
3052: [wc2013]糖果公园 Time Limit: 200 Sec Memory Limit: 512 MBSubmit: 883 Solved: 419[Submit][Status] ...
- 【WC2013】糖果公园
Candyland 有一座糖果公园,公园里不仅有美丽的风景.好玩的游乐项目,还有许多免费糖果的发放点,这引来了许多贪吃的小朋友来糖果公园玩. 糖果公园的结构十分奇特,它由 nn 个游览点构成,每个游览 ...
- UOJ #58 【WC2013】 糖果公园
题目链接:糖果公园 听说这是一道树上莫队的入门题,于是我就去写了--顺便复习了一下莫队的各种姿势. 首先,我们要在树上使用莫队,那么就需要像序列一样给树分块.这个分块的过程就是王室联邦这道题(vfle ...
- UOJ58 【WC2013】糖果公园
本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/ ...
- 洛谷 P4074 [WC2013]糖果公园 解题报告
P4074 [WC2013]糖果公园 糖果公园 树上待修莫队 注意一个思想,dfn序处理链的方法,必须可以根据类似异或的东西,然后根据lca分两种情况讨论 注意细节 Code: #include &l ...
随机推荐
- redis 学习笔记(二)
1. 在centos下安装g++,如果输入 yum install g++,那么将会提示找不到g++.因为在centos下g++安装包名字叫做:gcc-c++ 所以应该输入 yum install g ...
- Linux 进程管理 vmstat、top、pstree命令
vmstat命令:监控系统资源 vmstat 是 Linux 中的一个综合性能分析工具,可以用来监控 CPU 使用.进程状态.内存使用.虚拟内存使用.磁盘输入/输出状态等信息.vmstat 命令格式如 ...
- Ubuntu gcc错误:对'log'等函数未定义的引用
Ubuntu gcc错误:对'log'等函数未定义的引用 a.c #include <stdio.h>#include <math.h>int main(){ float ...
- Qt开发串口
首先,在工程文件里面, QT += serialport 在头文件里面, #include <QSerialPort> 1.配置打开串口 QSerialPort* myserial = n ...
- git diff提示filemode发生改变解决办法
git diff提示filemode发生改变(old mode 100644.new mode 10075) Posted on 2016-11-15 16:55 我是孙海龙 阅读(2292) 评论( ...
- 使用maven创建项目时报错The superclass "javax.servlet.http.HttpServlet" was not found on the Java Build Path
Description Resource Path Location Type The superclass "javax.servlet.http.HttpServlet" wa ...
- Shell 自定义函数
语法: function fname() { 程序段} 例子: #!/bin/bash ## 定义函数,分子除以分母,算利润.占有率等## 参数1:分子## 参数2:分母 function divfu ...
- IOS-SQLite数据库使用详解
使用SQLite数据库 创建数据库 创建数据库过程需要3个步骤: 1.使用sqlite3_open函数打开数据库: 2.使用sqlite3_exec函数执行Create Table语句,创建数据库表: ...
- linux的find命令详解
find命令是用来在给定的目录下查找符合给定条件的文件 find [OPTIONS] [查找起始路径] [查找条件] [处理动作] 一.OPTIONS参数 -P.-L.-H:控制软连接的对待方式, ...
- visualvm监控jvm及远程jvm监控方法
VisualVM是Sun的一个OpenJDK项目,其目的在于为Java应用创建一个整套的问题解决工具.它集成了多个JDK命令工具的一个可视化工具,它主要用来监控JVM的运行情况,可以用它来查看和浏览H ...