您的位置:首页 > 其它

「BZOJ3052」「WC2013」糖果公园

2017-12-26 22:21 381 查看

Description

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

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

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

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

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

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

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

输入格式

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

第二行包含 m 个正整数 v1,v2,…,vm。

第三行包含 n 个正整数 w1,w2,…,wn。

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

第 n+3 行包含 n 个正整数 c1,c2,…,cn。

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

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

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

输出格式

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

样例一

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


限制与约定

对于所有的数据,1≤vi,wi≤106,1≤ai,bi≤n,1≤ci≤m,w1,w2,…,wn 是非递增序列,即对任意 1<i≤n,满足 wi≤wi−1。

测试点编号nmq其它限制
1≤20≤20≤20
2≤2000≤2000≤2000
3≤10000≤10000≤10000
4≤80000≤100≤80000没有修改操作;给出的图构成一条链
5≤90000≤100≤90000
6≤80000≤80000≤80000没有修改操作
7≤90000≤90000≤90000
8≤80000≤80000≤80000给出的图构成一条链
9≤90000≤90000≤90000
10≤100000≤100000≤100000

题解

离线树上带修改莫队模板题。

树上莫队:

我们按照一种特殊的 dfs 序来代替点的位置,这种 dfs 序相邻点的距离小于 2 。

举个栗子:



的对应序列为 1→2→4→4→5→5→2→3→6→6→3→1 。

于是就可以像序列上的莫队一样分块了。

这样还有一个问题,就是统计不到当前左右端点的 LCA ,特判一下就好了。

再介绍一下带修改莫队:

带修改莫队,就是在普通莫队的基础上,每个询问再存储在它之前最后一次修改的编号 t 。

我们按照询问的左端点所在的块为第一关键字,右端点所在的块为第二关键字, t 为第三关键字排序,每次移动左右端点和修改指针。

由均值不等式,如果块的大小设置为 n23 时,时间复杂度最小,为 O(n53) 。具体证明请读者自己尝试。

本题就是把以上两种处理方法综合起来,就实现了树上带修改莫队。

复杂度 O(n53) (本题时限共 200s)。

My Code

不要像我一样手残把
pow(n, 2.0 / 3.0)
写成
pow(n, 2 / 3)
, 否则块的大小是 1 ,
TLE
了好几次。

/**************************************************************
Problem: 3052
User: infinityedge
Language: C++
Result: Accepted
Time:76306 ms
Memory:29824 kb
****************************************************************/

#include <iostream>
#include <cstring>
#include <cmath>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <vector>
#include <map>
#include <complex>

#define inf 0x3f3f3f3f
#define eps 1e-9
#define MAXN 1000000
using namespace std;
typedef long long ll;
const ll mod = 1e9 + 7;

struct edge{
int to, nxt;
}e[500005];

struct modify{
int x, y, z;
}d1[100005];

struct query{
int x, y, z, lc;
int px, py, id;
ll ans;
}d2[100005];

int cmp(query a, query b){
if(a.px != b.px) return a.px < b.px;
if(a.py != b.py) return a.py < b.py;
return a.z < b.z;
}

int cmp2(query a, query b){
return a.id < b.id;
}

int h[100005], cnt;

void addedge(int x, int y){
cnt++; e[cnt].to = y; e[cnt].nxt = h[x]; h[x] = cnt;
cnt++; e[cnt].to = x; e[cnt].nxt = h[y]; h[y] = cnt;
}

int n, m, q, k, q1, q2;
ll v[100005], w[100005];
int c[200005], rc[200005];
int id[200005], dfn, op[200005], f1[200005], f2[200005], fa[100005][18], dep[100005];
int bl[200005], ct[200005], vis[200005];

void dfs_belong(int x, int f){
fa[x][0] = f; dep[x] = dep[f] + 1;
id[++dfn] = x; f1[x] = dfn; op[dfn] = 1;
for(int i = h[x]; i; i = e[i].nxt){
if(e[i].to == f) continue;
dfs_belong(e[i].to, x);
}
id[++dfn] = x; f2[x] = dfn; op[dfn] = -1;
}

ll ans = 0;
void solvemodify(int p, int ad){
if(vis[d1[p].x]){
ans = ans - v[c[d1[p].x]] * w[ct[c[d1[p].x]]];
ct[c[d1[p].x]] --;
ans = ans + v[c[d1[p].x]] * w[ct[c[d1[p].x]]];
if(ad == 1){
ans = ans - v[d1[p].z] * w[ct[d1[p].z]];
ct[d1[p].z] ++;
ans = ans + v[d1[p].z] * w[ct[d1[p].z]];
}else{
ans = ans - v[d1[p].y] * w[ct[d1[p].y]];
ct[d1[p].y] ++;
ans = ans + v[d1[p].y] * w[ct[d1[p].y]];
}
}
if(ad == 1) c[d1[p].x] = d1[p].z; else c[d1[p].x] = d1[p].y;
}

void solvemove(int p, int ad){
if(ad == 1){
vis[p] = 1;
ans = ans - v[c[p]] * w[ct[c[p]]];
ct[c[p]] ++;
ans = ans + v[c[p]] * w[ct[c[p]]];
}else{
vis[p] = 0;
ans = ans - v[c[p]] * w[ct[c[p]]];
ct[c[p]] --;
ans = ans + v[c[p]] * w[ct[c[p]]];
}
}

int lca(int x, int y){
if(dep[x] < dep[y]) swap(x, y);
for(int i = 17; i >= 0; i --){
if(dep[fa[x][i]] >= dep[y]) x = fa[x][i];
}
if(x == y) return y;
for(int i = 17; i >= 0; i --){
if(fa[x][i] != fa[y][i]) x = fa[x][i], y = fa[y][i];
}
return fa[x][0];
}

void solve(){
int l = 1, r = 0, p = 0;
for(int i = 1; i <= q2; i ++){
while(r < d2[i].y){
r++;
solvemove(id[r], vis[id[r]] ^ 1);
}
while(l > d2[i].x){
l--;
solvemove(id[l], vis[id[l]] ^ 1);
}
while(r > d2[i].y){
solvemove(id[r], vis[id[r]] ^ 1);
r--;
}
while(l < d2[i].x){
solvemove(id[l], vis[id[l]] ^ 1);
l++;
}
int flag = 0;
if(!vis[d2[i].lc]) solvemove(d2[i].lc, 1), flag = 1;
while(p < d2[i].z){
p++;
solvemodify(p, 1);
}
while(p > d2[i].z){
solvemodify(p, -1);
p--;
}
d2[i].ans = ans;
if(flag) solvemove(d2[i].lc, 0);
}
}
int main(){
scanf("%d%d%d", &n, &m, &q);
k = max(int(pow(n, 2.0 / 3.0) / 2), 1);
for(int i = 1; i <= m; i ++){
scanf("%lld", &v[i]);
}
for(int i = 1; i <= n; i ++){
scanf("%lld", &w[i]);
w[i] += w[i - 1];
}
for(int i = 1; i < n; i ++){
int x, y;
scanf("%d%d", &x, &y);
addedge(x, y);
}
for(int i = 1; i <= n; i ++){
scanf("%d", &c[i]);
rc[i] = c[i];
}
for(int i = 1; i <= q; i ++){
int opt, x, y;
scanf("%d%d%d", &opt, &x, &y);
if(opt == 0){
q1++; d1[q1].x = x; d1[q1].y = rc[x]; rc[x] = y; d1[q1].z = rc[x];
}else{
q2++; d2[q2].x = x; d2[q2].y = y; d2[q2].z = q1;  d2[q2].id = q2;
}
}
dfs_belong(1, 0);
for(int j = 1; j <= 17; j ++){
for(int i = 1; i <= n; i ++){
fa[i][j] = fa[fa[i][j - 1]][j - 1];
}
}
for(int i = 1; i <= 2 * n; i ++){
bl[i] = (i - 1) / k + 1;
}
for(int i = 1; i <= q2; i ++){
if(f1[d2[i].x] > f1[d2[i].y]) swap(d2[i].x, d2[i].y);
d2[i].lc = lca(d2[i].x, d2[i].y);
if(f2[d2[i].x] < f1[d2[i].y]) d2[i].x = f2[d2[i].x]; else d2[i].x = f1[d2[i].x] ;
d2[i].y = f1[d2[i].y];
d2[i].px = bl[d2[i].x];
d2[i].py = bl[d2[i].y];
}
sort(d2 + 1, d2 + q2 + 1, cmp);
solve();
sort(d2 + 1, d2 + q2 + 1, cmp2);
for(int i = 1; i <= q2; i ++){
printf("%lld\n", d2[i].ans);
}
return 0;
}

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息