【题目描述】

UOJ 好咯。

【题目链接】

UOJ 58 糖果公园 【WC 2013】

BZOJ 3052 糖果公园

【解题思路】

树上带修改莫队,详见 莫队算法 - 学习笔记

【AC代码】

祝大家一遍 A 掉,反正我没能做到,还好我做这题时没啥人...

#include <cstdio>
#include <algorithm>
#include <cmath>

namespace io{
    const int INSIZE = 1 << 15, OTSIZE = 1 << 20;
    char inBuf[INSIZE], otBuf[OTSIZE], *S, *T, ch;
    int now;

    inline void init(){
        S = T = NULL;
        now = 0;
    }

    inline int getchar(){
        if(S == T) S = inBuf, T = inBuf + fread(inBuf, 1, INSIZE, stdin);
        if(S == T) return EOF;
        return *S++;
    }

    template<typename Int>
    inline void readint(Int &x){
        Int f = 1;
        for(ch = getchar(); ch < '0' || ch > '9'; ch = getchar()) if(ch == '-') f = -1;
        for(x = 0; ch >= '0' && ch <= '9'; ch = getchar()) x = (x << 1) + (x << 3) + (ch ^ '0');
        x *= f;
    }

    inline void flush(){
        if(now) fwrite(otBuf, 1, now, stdout), now = 0;
    }

    inline void putchar(char ch){
        otBuf[now++] = ch;
        if(now == OTSIZE) flush();
    }

    template<typename Int>
    inline void putint(Int x){
        if(x < 0) putchar('-'), putint(-x);
        else{
            if(x > 9) putint(x / 10);
            putchar(x % 10 + '0');
        }
    }

    inline void br(){
        putchar('\n');
    }

    inline void close(){
        flush();
    }
}

typedef long long int64;

const int MAXN = 100000;
const int MAXM = 100000;
const int MAXL = 2 * MAXN - 1;
const int MAXLOGL = 18;
const int MAXQ = 100000;

struct Node{
    struct Edge *edges;
    Node *fa;

    int candy;

    int id, pos, blockId, depth;
    bool in;
} nodes[MAXN];

struct Edge{
    Node *to;
    Edge *next;

    Edge() {}
    Edge(Node *fr, Node *to) : to(to), next(fr->edges) {}
} epool[2 * (MAXN - 1)], *eptr = epool;

inline void link(Node *u, Node *v){
    u->edges = new (eptr++) Edge(u, v);
    v->edges = new (eptr++) Edge(v, u);
}

int n, m, q;

int value[MAXM + 1], curiosity[MAXN + 1];

int64 ans[MAXM];

Node *f[MAXL][MAXLOGL + 1];
int logBase2[MAXL + 1];
int len;

Node *S[MAXN];
int top;
int blockCnt, blockSize;

inline void dfs(Node *v, Node *fa = NULL){
    static int dfsClock = 0;
    v->id = ++dfsClock;

    f[v->pos = len++][0] = v;

    int bot = top;
    for(Edge *e = v->edges; e; e = e->next) if(!e->to->depth){
        e->to->depth = v->depth + 1, e->to->fa = v, dfs(e->to);
        if(top - bot >= blockSize){
            while(top > bot) S[--top]->blockId = blockCnt;
            blockCnt++;
        }

        f[len++][0] = v;
    }

    S[top++] = v;
}

inline Node* min(Node *a, Node *b){
    return a->depth < b->depth ? a : b;
}

inline Node* rmq(int l, int r){
    int k = logBase2[r - l + 1];
    return min(f[l][k], f[r - (1 << k) + 1][k]);
}

inline Node* queryLCA(Node *a, Node *b){
    if(a->pos > b->pos) std::swap(a, b);
    return rmq(a->pos, b->pos);
}

void build(){
    blockSize = int(std::ceil(std::pow(n, 2.0 / 3.0) + 1e-6));
    nodes->depth = 1, nodes->fa = NULL, dfs(nodes);
    while(top) S[--top]->blockId = blockCnt - 1;

    logBase2[1] = 0;
    for(int i = 2; i <= len; i++) logBase2[i] = logBase2[i >> 1] + 1;
    
    for(int k = 1; k <= logBase2[len]; k++){
        for(int i = 0; i < len; i++){
            if(i + (1 << k - 1) < len){
                f[i][k] = min(f[i][k - 1], f[i + (1 << k - 1)][k - 1]);
            } else{
                f[i][k] = f[i][k - 1];
            }
        }
    }
}

struct Modification{
    Node *pos;
    int candy;
} modifications[MAXQ];

struct Query{
    Node *u, *v;
    int id, time;

    inline friend bool operator<(const Query &a, const Query &b){
        if(a.u->blockId != b.u->blockId) return a.u->blockId < b.u->blockId;
        else if(a.v->blockId != b.v->blockId) return a.v->blockId < b.v->blockId;
        else return a.time < b.time;
    }
} querys[MAXQ];

int mcnt, qcnt;

int buc[MAXN];
int64 currAns;

inline int64 contribution(int candy){
    return (int64)value[candy] * curiosity[ buc[candy] ];
}

inline void flip(Node *v){
    v->in ^= 1;
    if(v->in){
        ++buc[v->candy];

        currAns += contribution(v->candy);
    } else{
        currAns -= contribution(v->candy);

        --buc[v->candy];
    }
}

inline void flip(Node *u, Node *v){
    Node *lca = queryLCA(u, v);
    for(Node *p = u; p != lca; p = p->fa) flip(p);
    for(Node *p = v; p != lca; p = p->fa) flip(p);
}

inline void flipModification(int time){
    Modification *o = modifications + time;

    bool in = o->pos->in;

    if(in) flip(o->pos);
    std::swap(o->candy, o->pos->candy);
    if(in) flip(o->pos);
}

inline void solve(){
    std::sort(querys, querys + qcnt);

    Node *u = nodes, *v = nodes, *lca = nodes;
    flip(nodes);
    int currTime = 0;
    for(Query *q = querys; q != querys + qcnt; q++){
        while(currTime < q->time) flipModification(currTime++);
        while(currTime > q->time) flipModification(--currTime);

        flip(lca);
        lca = queryLCA(q->u, q->v);
        flip(lca);

        flip(u, q->u), u = q->u;
        flip(v, q->v), v = q->v;

        ans[q->id] = currAns;
    }
}

int main(){
    io::init();

    io::readint(n), io::readint(m), io::readint(q);
    for(int i = 1; i <= m; i++) io::readint(value[i]);
    for(int i = 1; i <= n; i++) io::readint(curiosity[i]);
    for(int i = 0, u, v; i < n - 1; i++){
        io::readint(u), io::readint(v), u--, v--;

        link(nodes + u, nodes + v);
    }
    for(Node *v = nodes; v != nodes + n; v++) io::readint(v->candy);

    build();

    for(int i = 0; i < q; i++){
        int t;
        io::readint(t);

        if(t == 1){ // Query
            Query *q = querys + qcnt;

            int u, v;
            io::readint(u), io::readint(v), u--, v--;
            q->u = nodes + u, q->v = nodes + v, q->id = qcnt, q->time = mcnt;

            if(q->v->id > q->u->id) std::swap(q->u, q->v);

            qcnt++;
        } else if(t == 0){ // Modification
            Modification *o = modifications + mcnt;

            int pos, candy;
            io::readint(pos), io::readint(candy), pos--;
            o->pos = nodes + pos, o->candy = candy;

            mcnt++;
        } else{
            throw;
        }
    }

    solve();

    for(int i = 0; i < qcnt; i++) io::putint(ans[i]), io::br();

    io::close();
    return 0;
}

就是这样咯~