WC2013 糖果公园 带修改树上莫队

题目链接点我点我:-)
题目描述
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 的操作输出一行,用一个正整数表示答案。

思路
经典的带修改树上莫队,这是一个很好的讲解,这位同学用的是类似BZOJ1086的分块方法
但是我的树分块方法不同,我是先把树转为括号序列再做序列上的莫队.

感想
第一次写树上莫队和带修改的莫队,从上午开始写,写了一天.然后交UOJ,T飞了.结果发现自己分的是假块,应该分n的三分之二次方一块,但是我看错了分成了n的三分之一次方一块.

代码

50分

//miaomiao 2017.3.28
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>

using namespace std;

#define LL long long
#define getchar getchar_unlocked
#define Set(a, v) memset(a, v, sizeof(a))
#define For(i, a, b) for(int i = (a); i <= (int)(b); ++i)
#define N (100000+5)

char ch;
inline void read(int &x){
    ch = getchar();
    while(ch < '0' || ch > '9') ch = getchar();
    x = 0;
    while(ch >= '0' && ch <= '9'){
        x = (x<<1)+(x<<3)+(ch^'0'); ch = getchar(); 
    }
}

int n, m, rv[N], w[N], c[N], fa[N], myn[N], cnt[N];
int en, head[N], nxt[N<<1], to[N<<1];
bool vis[N];
LL sumw[N];

int beg, idn, id[N], sum[105][N];

inline void Add(int a, int b){
    to[++en] = b; nxt[en] = head[a]; head[a] = en;
}

void dfs(int now, int F){
    fa[now] = F;

    bool in = false;
    for(int i = head[now]; i; i = nxt[i]){
        if(F == to[i]) continue;
        dfs(to[i], now); in = true;
    }
    if(!in) beg = now;
}

void dfs2(int now, int F){
    id[now] = ++idn;
    For(i, 1, m) sum[i][idn] = sum[i][idn-1];
    ++sum[c[now]][idn];

    for(int i = head[now]; i; i = nxt[i])
        if(F != to[i]) dfs2(to[i], now);
}

inline void calc_bf(int u, int v){
    int x = u, y = v, lca;

    Set(vis, 0);
    while(x) vis[x] = true, x = fa[x];
    while(y){
        if(vis[y]){lca = y; break;}
        myn[fa[y]] = y; y = fa[y];
    }

    Set(cnt, 0); x = u; y = lca;
    while(x != lca) ++cnt[c[x]], x = fa[x];
    while(y != v) ++cnt[c[y]], y = myn[y];
    ++cnt[c[y]];

    LL ans = 0;
    For(i, 1, m) ans += sumw[cnt[i]]*rv[i];
    printf("%lld\n", ans);
}

inline void swp(int &a, int &b){
    a ^= b ^= a ^= b;
}

inline void solve(int u, int v){
    u = id[u], v = id[v];
    if(u > v) swp(u, v);

    LL ans = 0;
    For(i, 1, m)
        ans += sumw[sum[i][v]-sum[i][u-1]]*rv[i];
    printf("%lld\n", ans);
}

int main(){
#ifndef ONLINE_JUDGE
    freopen("test.in", "r", stdin);
    freopen("test.out", "w", stdout);
#endif

    int q, t, u, v;

    read(n); read(m); read(q);
    For(i, 1, m) read(rv[i]);
    For(i, 1, n) read(w[i]), sumw[i] = sumw[i-1]+w[i];
    For(i, 1, n-1){
        read(u); read(v);
        Add(u, v); Add(v, u);
    }
    For(i, 1, n) read(c[i]);
    dfs(1, 0); if(m <= 100 && n > 100) dfs2(beg, 0);

    while(q--){
        read(t); read(u); read(v);
        if(!t){c[u] = v; continue;}

        if(m<=100 && n > 100){solve(u, v); continue;}
        calc_bf(u, v);
    }

    return 0;
}

100分

//miaomiao 2017.3.29
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<vector>

using namespace std;

#define LL long long
#define pb push_back
#define getchar getchar_unlocked
#define For(i, a, b) for(int i = (a); i <= (int)(b); ++i)
#define Forr(i, a, b) for(int i = (a); i >= (int)(b); --i)

#define N (100000+2)
#define LOG 18

char ch;
inline void read(int &x){
    ch = getchar();
    while(ch < '0' || ch > '9') ch = getchar();
    x = 0;
    while(ch >= '0' && ch <= '9'){
        x = (x<<1)+(x<<3)+(ch^'0'); ch = getchar(); 
    }
}

inline void swp(int &a, int &b){a^=b^=a^=b;}
struct node{int a, b, be;};

int f[N][LOG], blo[N<<1];

struct Qus{
    int L, R, t, lca;

    bool operator <(const Qus &rhs)const{
        if(blo[L] != blo[rhs.L]) return blo[L] < blo[rhs.L];
        if(blo[R] != blo[rhs.R]) return blo[R] < blo[rhs.R];
        return t < rhs.t;
    }
}qus[N];

int n, m, q, qn, qusn;
int rv[N], w[N], c[N], uc[N], fir[N], sec[N], dep[N], ql[N<<1];
int en, head[N], to[N<<1], nxt[N<<1], ccnt[N];
bool vis[N];
vector<node> TU[N];
LL ans, Ans[N];

inline void Add(int a, int b){
    to[++en] = b; nxt[en] = head[a]; head[a] = en;
}

inline void dfs(int now, int F, int D){
    ql[++qn] = now; fir[now] = qn; dep[now] = D;
    f[now][0] = F;

    for(int i = head[now]; i; i = nxt[i]){
        if(to[i] == F) continue;
        dfs(to[i], now, D+1);
    }

    ql[++qn] = now; sec[now] = qn;
}

inline void rmq_init(){
    For(j, 1, 17) For(i, 1, n)
        f[i][j] = f[f[i][j-1]][j-1];
}

inline int Lca(int u, int v){
    if(dep[u] < dep[v]) swp(u, v);

    for(int k = 17; k >= 0; --k)
        if(dep[f[u][k]] >= dep[v]) u = f[u][k];
    if(u == v) return u;

    for(int k = 17; k >= 0; --k)
        if(f[u][k]^f[v][k]) u = f[u][k], v = f[v][k];
    return f[u][0];
}

inline int CalcPos(int &L, int &R){
    if(fir[L] > fir[R]) swp(L, R);

    int lca = Lca(L, R);

    if(lca == R || lca == L) L = fir[L], R = fir[R]; 
    else L = sec[L], R = fir[R];
    if(L > R) swp(L, R);

    return lca;
}

inline void Moy(int now){
    now = ql[now]; vis[now] ^= 1;
    if(vis[now]) ++ccnt[c[now]], ans += 1ll*w[ccnt[c[now]]]*rv[c[now]];
    else ans -= 1ll*w[ccnt[c[now]]]*rv[c[now]], --ccnt[c[now]]; 
}

inline void Chg(int a, int b){
    if(vis[a]){Moy(fir[a]); c[a] = b; Moy(fir[a]);}
    else c[a] = b;
}

int main(){
#ifndef ONLINE_JUDGE
    freopen("test.in", "r", stdin);
    freopen("test.out", "w", stdout);
#endif

    int op, u, v, rq;
    read(n); read(m); read(rq);
    For(i, 1, m) read(rv[i]); For(i, 1, n) read(w[i]);

    For(i, 1, n-1){
        read(u); read(v);
        Add(u, v); Add(v, u);
    }
    For(i, 1, n) read(c[i]), uc[i] = c[i];

    int siz = (int)pow(n<<1, 2.0/3);
    dfs(1, 0, 1); rmq_init();

    For(i, 1, n<<1) blo[i] = (i-1)/siz;

    int last = 0, lca;
    For(i, 1, rq){
        read(op); read(u); read(v);
        if(!op){
            if(!last){c[u] = uc[u] = v; continue;}
            TU[last].pb((node){u, v, uc[u]}); uc[u] = v;
            continue;
        }
        lca = CalcPos(u, v); ++qusn;
        qus[qusn] = (Qus){u, v, qusn, lca}; last = qusn;
    }
    sort(qus+1, qus+qusn+1);

    int L = 1, R = 0, ml, mr, mt, T = 0;
    For(i, 1, qusn){
        ml = qus[i].L, mr = qus[i].R; mt = qus[i].t;

        while(T < mt){
            For(j, 0, TU[T].size()-1) Chg(TU[T][j].a, TU[T][j].b);
            ++T;
        }
        while(T > mt){
            --T;
            Forr(j, TU[T].size()-1, 0) Chg(TU[T][j].a, TU[T][j].be);
        }

        while(L > ml) Moy(--L); while(L < ml) Moy(L++); 
        while(R < mr) Moy(++R); while(R > mr) Moy(R--);

        lca = qus[i].lca;
        if(ql[ml] != lca && ql[mr] != lca){
            Moy(fir[lca]); Ans[qus[i].t] = ans; Moy(fir[lca]);
        }else Ans[qus[i].t] = ans;
    }
    For(i, 1, qusn) printf("%lld\n", Ans[i]);

    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值