【Luogu P4074】[WC2013]糖果公園(樹上帶修改莫隊)

題目描述

Candyland 有一座糖果公園,公園裏不只有美麗的風景、好玩的遊樂項目,還有許多免費糖果的發放點,這引來了許多貪吃的小朋友來糖果公園遊玩。html

糖果公園的結構十分奇特,它由 \(n\) 個遊覽點構成,每一個遊覽點都有一個糖果發放處,咱們能夠依次將遊覽點編號爲 \(1\)\(n\)。有 \(n-1\) 條雙向道路鏈接着這些遊覽點,而且整個糖果公園都是連通的,即從任何一個遊覽點出發均可以經過這些道路到達公園裏的全部其它遊覽點。git

糖果公園所發放的糖果種類很是豐富,總共有 \(m\) 種,它們的編號依次爲 \(1\)\(m\)。每個糖果發放處都只發放某種特定的糖果,咱們用 \(C_i\) 來表示 \(i\) 號遊覽點的糖果。spa

來到公園裏遊玩的遊客都不喜歡走回頭路,他們老是從某個特定的遊覽點出發前往另外一個特定的遊覽點,並遊覽途中的景點,這條路線必定是惟一的。他們通過每一個遊覽點,均可以品嚐到一顆對應種類的糖果。code

你們對不一樣類型糖果的喜好程度都不盡相同。 根據遊客們的反饋打分,咱們獲得了糖果的美味指數, 第 \(i\) 種糖果的美味指數爲 \(V_i\) 。另外,若是一位遊客反覆地品嚐同一種類的糖果,他確定會以爲有一些膩。根據量化統計,咱們獲得了遊客第 \(i\) 次品嚐某類糖果的新奇指數 \(W_i\) 。若是一位遊客第 \(i\) 次品嚐第 \(j\) 種糖果,那麼他的愉悅指數 \(H\) 將會增長對應的美味指數與新奇指數的乘積,即 \(V_j×W_i\) 。這位遊客遊覽公園的愉悅指數最終將是這些乘積的和。htm

固然,公園中每一個糖果發放點所發放的糖果種類不必定是一成不變的。有時,一些糖果點所發放的糖果種類可能會更改(也只會是 \(m\) 種中的一種),這樣的目的是可以讓遊客們老是感覺到驚喜。blog

糖果公園的工做人員小 A 接到了一個任務,那就是根據公園最近的數據統計出每位遊客遊玩公園的愉悅指數。但數學很差的小 A 一看到密密麻麻的數字就以爲頭暈,做爲小 A 最好的朋友,你決定幫他一把。get

輸入輸出格式

輸入格式:

從文件 park.in 中讀入數據。qt

第一行包含三個正整數 \(n\), \(m\), \(q\), 分別表示遊覽點個數、 糖果種類數和操做次數。數學

第二行包含 \(m\) 個正整數 \(V_1,V_2,...,V_m\)string

第三行包含 \(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\) 的路線詢問愉悅指數。

輸出格式:

輸出到文件 park.out 中。

按照輸入的前後順序,對於每一個 \(Type\)\(1\) 的操做輸出一行,用一個正整數表示答案。

輸入輸出樣例

輸入樣例#1:

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

輸出樣例#1:

84
131
27
84

總體思路

樹上莫隊+帶修莫隊=樹上帶修莫隊,若是不懂能夠看這裏

莫隊添加數值時,添加的數值(添加的結點發的糖,記爲\(c\))對答案的貢獻爲\(V_c × W_{cnt_c}\),在端點、修改點、lca暴力添加便可。刪除亦然。

code:

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
#define maxn 200200
#define ll long long
int cnt[maxn], aa[maxn], belong[maxn], inp[maxn], n, m, Q, ncnt, size, bnum, w[maxn], v[maxn], ccnt, qcnt;
int val[maxn], fa[maxn][30], depth[maxn], head[maxn], ecnt;
int fir[maxn], la[maxn], vis[maxn];
int l = 1, r = 0, t = 0;
ll now, ans[maxn];
struct edge {
    int to, next;
} e[maxn];
void adde(int u, int v) {
    e[++ecnt] = (edge){v, head[u]};
    head[u] = ecnt;
    e[++ecnt] = (edge){u, head[v]};
    head[v] = ecnt;
}
void dfs(int x) {
    aa[++ncnt] = x;
    fir[x] = ncnt;
    for(int k = head[x]; k; k = e[k].next) {
        int to = e[k].to;
        if(depth[to]) continue;
        depth[to] = depth[x] + 1;
        fa[to][0] = x;
        for(int i = 1; (1 << i) <= depth[to]; ++i) fa[to][i] = fa[fa[to][i - 1]][i - 1];
        dfs(to);
    }
    aa[++ncnt] = x;
    la[x] = ncnt;
}
int getlca(int u, int v) {
    if(depth[u] < depth[v]) swap(u, v);
    for(int i = 20; i + 1; --i) if(depth[fa[u][i]] >= depth[v]) u = fa[u][i];
    if(u == v) return u;
    for(int i = 20; i + 1; --i) if(fa[u][i] != fa[v][i]) u = fa[u][i], v = fa[v][i];
    return fa[u][0];
}
struct query {
    int l, r, id, lca, t;
} q[maxn];
int cmp(query a, query b) {
    return (belong[a.l] ^ belong[b.l]) ? belong[a.l] < belong[b.l] : ((belong[a.r] ^ belong[b.r]) ? belong[a.r] < belong[b.r] : a.t < b.t );
}
inline void add(int pos) {
    now += 1ll * v[val[pos]] * w[++cnt[val[pos]]];
}
inline void del(int pos) {
    now -= 1ll * v[val[pos]] * w[cnt[val[pos]]--];
}
inline void work(int pos) {
    vis[pos] ? del(pos) : add(pos);
    vis[pos] ^= 1;
}
struct change {
    int pos, val;
} ch[maxn];
void modify(int x) {
    if(vis[ch[x].pos]) {
        work(ch[x].pos);
        swap(val[ch[x].pos], ch[x].val);
        work(ch[x].pos);
    }
    else swap(val[ch[x].pos], ch[x].val);
}
#define isdigit(x) ((x) >= '0' && (x) <= '9')
inline int read() {
    int res = 0;
    char c = getchar();
    while(!isdigit(c)) c = getchar();
    while(isdigit(c)) res = (res << 1) + (res << 3) + (c ^ 48), c = getchar();
    return res;
}
int main() {
    n = read(), m = read(), Q = read();
    for(int i = 1; i <= m; ++i) v[i] = read();
    for(int i = 1; i <= n; ++i) w[i] = read();
    for(int i = 1; i < n; ++i) {
        int u = read(), v = read();
        adde(u, v);
    }
    for(int i = 1; i <= n; ++i) val[i] = read();
    depth[1] = 1;
    dfs(1);
    size = pow(ncnt, 2.0 / 3.0);
    bnum = ceil((double)ncnt / size);
    for(int i = 1; i <= bnum; ++i)
        for(int j = size * (i - 1) + 1; j <= i * size; ++j) belong[j] = i;
    for(int i = 1; i <= Q; ++i) {
        int opt = read(), a = read(), b = read();
        if(opt) {
            int lca = getlca(a, b);
            q[++qcnt].t = ccnt;
            q[qcnt].id = qcnt;
            if(fir[a] > fir[b]) swap(a, b);
            if(a == lca) q[qcnt].l = fir[a], q[qcnt].r = fir[b];
            else q[qcnt].l = la[a], q[qcnt].r = fir[b], q[qcnt].lca = lca;
        }
        else {
            ch[++ccnt].pos = a;
            ch[ccnt].val = b;
        }
    }
    sort(q + 1, q + qcnt + 1, cmp);
    for(int i = 1; i <= qcnt; ++i) {
        int ql = q[i].l, qr = q[i].r, qt = q[i].t, qlca = q[i].lca;
        while(l < ql) work(aa[l++]);
        while(l > ql) work(aa[--l]);
        while(r < qr) work(aa[++r]);
        while(r > qr) work(aa[r--]);
        while(t < qt) modify(++t);
        while(t > qt) modify(t--);
        if(qlca) work(qlca);
        ans[q[i].id] = now;
        if(qlca) work(qlca);
    }
    for(int i = 1; i <= qcnt; ++i) printf("%lld\n", ans[i]);
    return 0;
}
相關文章
相關標籤/搜索