Description
Candyland 有一座糖果公园,公园里不仅有美丽的风景、好玩的游乐项目,还有许多免费糖果的发放点,这引来了许多贪吃的小朋友来糖果公园玩。
糖果公园的结构十分奇特,它由
n
个游览点构成,每个游览点都有一个糖果发放处,我们可以依次将游览点编号为
糖果公园所发放的糖果种类非常丰富,总共
m
种,它们的编号依次为
来到公园里游玩的游客都不喜欢走回头路,他们总是从某个特定的游览点出发前往另一个特定的游览点,并游览途中的景点,这条路线一定是唯一的。他们经过每个游览点,都可以品尝到一颗对应种类的糖果。
大家对不同类型的糖果的喜爱程度都不尽相同。根据游客们的反馈打分,我们得到了糖果的美味指数,第
当然,公园中每个糖果发放点所发放的糖果种类不一定是一成不变的。有时,一些糖果点所发放的糖果种类可能会更改(也只会是 m 种中的一种),这样的目的是能够让游客们总是感受到惊喜。
糖果公园的工作人员小 A 接到了一个任务,那就是根据公园最近的数据统计出每位游客游玩公园的愉悦指数。但数学不好的小 A 一看到密密麻麻的数字就觉得头晕,作为小 A 最好的朋友,你决定帮他一把。
输入格式
第一行包含三个正整数
第二行包含
m
个正整数
第三行包含
n
个正整数
第四行到第 n+2 行,每行包含两个正整数 ai,bi ,表示这两个游览点之间有路径可以直接到达。
第
n+3
行包含
n
个正整数
接下来
q
行,每行包含三个整数
若
t
为
若
t
为
输出格式
按照输入的先后顺序,对于每个
t
为
样例一
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 。
测试点编号 | n | q | 其它限制 | |
---|---|---|---|---|
1 | ≤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
。
举个栗子:
的对应序列为
于是就可以像序列上的莫队一样分块了。
这样还有一个问题,就是统计不到当前左右端点的 LCA ,特判一下就好了。
再介绍一下带修改莫队:
带修改莫队,就是在普通莫队的基础上,每个询问再存储在它之前最后一次修改的编号
t
。
我们按照询问的左端点所在的块为第一关键字,右端点所在的块为第二关键字,
由均值不等式,如果块的大小设置为
n23
时,时间复杂度最小,为
O(n53)
。具体证明请读者自己尝试。
本题就是把以上两种处理方法综合起来,就实现了树上带修改莫队。
复杂度 O(n53) (本题时限共 200s )。
My Code
不要像我一样手残把 pow(n, 2.0 / 3.0)
写成 pow(n, 2 / 3)
, 否则块的大小是
1
<script type="math/tex" id="MathJax-Element-95">1</script> , 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;
}