1. 程式人生 > >【WC2013】 糖果公園 - 樹上莫隊

【WC2013】 糖果公園 - 樹上莫隊

最好 fin 結構 我們 .cn read i++ put href

【問題描述】

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 最好的朋友,你決定幫他一把。
【輸入文件】
從文件 park.in 中讀入數據。
第一行包含三個正整數 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 的路線詢問愉悅指數。
【輸出文件】
輸出到文件 park.out 中。
按照輸入的先後順序,對於每個 Type 為 1 的操作輸出一行,用一個正整數
表示答案。

思路

樹上莫隊模板題,莫隊算法詳見『這裏』

#include <bits/stdc++.h>
#define ri register
using namespace std;
typedef long long ll;
const int maxn = 100000 + 10;
int n,m,Q,cntq,cntc,Time,block,mark[maxn],dep[maxn],cnt[maxn],father[maxn][20],dfn[maxn],v[maxn],w[maxn],x[maxn],edgecnt,first[maxn];
ll tot,ans[maxn];
struct edge {
    int to,next;
}eg[maxn];
inline void addedge(ri int u,ri int v){
    eg[++edgecnt] = (edge){v,first[u]}; first[u] = edgecnt;
    eg[++edgecnt] = (edge){u,first[v]}; first[v] = edgecnt;
}
inline int read() {
    char ch = getchar();
    ri int x = 0, f = 1;
    while  (ch < 0 || ch > 9) {
        if (ch == -) f = -1;
        ch = getchar();
    }
    while (0 <= ch && ch <= 9) {
        x = x * 10 + ch - 0;
        ch = getchar();
    }
    return x * f;
}
void write(ll x) {
    ri ll y = 10,len = 1;
    while (y <= x) { y *= 10; len++; }
    while (len--) { y /= 10; putchar(x/y+48); x %= y; }
}
struct Query {
    int l,r,num,c;
    inline bool operator < (Query cmp) const {
        if (dfn[l]/block != dfn[cmp.l]/block) return dfn[l]/block < dfn[cmp.l]/block;
        if (dfn[r]/block != dfn[cmp.r]/block) return dfn[r]/block < dfn[cmp.r]/block;
        return c < cmp.c;
    }
}q[maxn];
struct Change {
    int pos,to;
}c[maxn];
inline void dfs(ri int now,ri int fa) {
    father[now][0] = fa;
    dfn[now] = ++Time;
    dep[now] = dep[fa]+1;
    ri size_t i;
    for (i = first[now];~i;i = eg[i].next)
        if (eg[i].to != fa) dfs(eg[i].to,now);
}
inline void init() {
    ri int i,j;
    for (j = 1;(1<<j) <= n;j++)
        for (i = 1;i <= n;i++)
            father[i][j] = father[father[i][j-1]][j-1];
}
inline int lca(ri int a,ri int b) {
    if (dep[a] < dep[b]) swap(a,b);
    ri int i,j; for (i = 0;(1<<i) <= dep[a];i++); i--;
    for (j = i;j >= 0;j--)
        if (dep[a]-(1<<j) >= dep[b]) a = father[a][j];
    if (a == b) return a;
    for (j = i;j >= 0;j--)
        if (father[a][j] != father[b][j]) a = father[a][j],b = father[b][j];
    return father[a][0];
}
inline void reverse(ri int i) {
    if (mark[i]) { mark[i] ^= 1; tot -= (long long)w[cnt[x[i]]--]*(long long)v[x[i]]; }
    else { mark[i] ^= 1; tot += (long long)w[++cnt[x[i]]]*(long long)v[x[i]]; }
}
inline void change(ri int i) {
    if (!mark[c[i].pos]) swap(c[i].to,x[c[i].pos]);
    else {
        reverse(c[i].pos);
        swap(c[i].to,x[c[i].pos]);
        reverse(c[i].pos);
    }
}
int main() {
    memset(first,-1,sizeof(first));
    n = read(),m = read(),Q = read();
    block = pow(n,2.0/3)*0.5;
    ri int i,t,X,y;
    for (i = 1;i <= m;i++) v[i] = read();
    for (i = 1;i <= n;i++) w[i] = read();
    for (i = 1;i < n;i++) X = read(),y = read(),addedge(X,y);
    for (i = 1;i <= n;i++) x[i] = read();
    dfs(1,0);
    init();
    for (i = 1;i <= Q;i++) {
        t = read(),X = read(),y = read();
        if (!t) c[++cntc].pos = X,c[cntc].to = y;
        else q[++cntq].l = X,q[cntq].r = y,q[cntq].num = cntq,q[cntq].c = cntc;
    }
    sort(q+1,q+cntq+1);
    if (dfn[q[1].l] > dfn[q[1].r]) swap(q[1].l,q[1].r);
    ri ll LCA  = lca(q[1].l,q[1].r),curl = q[1].l,curr = q[1].r,curc = 0,l = curl,r = curr;
    while (l != LCA) reverse(l),l = father[l][0];
    while (r != LCA) reverse(r),r = father[r][0];
    while (curc < q[1].c) change(++curc);
    reverse(LCA); ans[q[1].num] = tot; reverse(LCA);
    for (i = 2;i <= cntq;i++) {
        if (dfn[q[i].l] > dfn[q[i].r]) swap(q[i].l,q[i].r);
        LCA = lca(q[i].r,curr),l = curr,r = q[i].r;
        while (l != LCA) reverse(l),l = father[l][0];
        while (r != LCA) reverse(r),r = father[r][0];
        LCA = lca(q[i].l,curl),l = curl,r = q[i].l;
        while (l != LCA) reverse(l),l = father[l][0];
        while (r != LCA) reverse(r),r = father[r][0];
        while (curc < q[i].c) change(++curc);
        while (curc > q[i].c) change(curc--);
        LCA = lca(q[i].l,q[i].r);
        reverse(LCA); ans[q[i].num] = tot; reverse(LCA);
        curl = q[i].l,curr = q[i].r;
    }
    for (i = 1;i <= cntq;i++) write(ans[i]),putchar(\n);
    return 0;
}

【WC2013】 糖果公園 - 樹上莫隊