#58. 【WC2013】糖果公园

虽然是个树上莫队裸题还是一遍a
但是发现这题不简单,因为洛谷卡常…
在uoj上过了发现洛谷只过了三个点,
然后各种卡常总算过了
c++代码如下:

#include<bits/stdc++.h>
#define rep(i,x,y) for(register int i = x ; i <= y;++ i)
#define repd(i,x,y) for(register int i = x ; i >= y; -- i)
using namespace std;
typedef long long ll ;
inline char gc(){
    static char now[1<<16],*S,*T;
    if (T==S){T=(S=now)+fread(now,1,1<<16,stdin);if (T==S) return EOF;}
    return *S++;
}
template<typename T>inline void read(T&x)
{
    x = 0;char c;int sign = 1;
    do { c = gc(); if(c == '-') sign = -1; }while(!isdigit(c));
    do { x = x * 10 + c - '0'; c = gc(); }while(isdigit(c));
    x *= sign;
}


const int N = 2e5+500;
int n,m,q,d,sz,size[N],top[N],hson[N];
ll v[N],w[N],c[N],ans[N];
int head[N],nxt[N],to[N],tot;
int id[N],lst[N],deep[N],belong[N],f[N];
struct Data { int x,y,t,lst; }que[N],mod[N];
bool vis[N];int num[N];ll sum;

const bool cmp(Data a,Data b)
{
    if(belong[a.x] != belong[b.x]) return belong[a.x] < belong[b.x];
    if(belong[a.y] != belong[b.y]) return belong[a.y] < belong[b.y];
    return a.t < b.t;
}

inline void add(int x,int y)
{
    nxt[tot] = head[x];
    to[tot] = y;
    head[x] = tot++;
}

void dfs(int x)
{
    size[x] = 1;
    for(register int i = head[x];~i;i=nxt[i])
        if(to[i] != f[x])
        {
            deep[to[i]] = deep[x] + 1;
            f[to[i]] = x;
            dfs(to[i]);
            size[x] += size[to[i]];
            if(size[hson[x]] < size[to[i]])
                hson[x] = to[i];
        }
}

void dfs2(int x,int t)
{
    top[x] = t;id[x] = ++ sz;
    if(hson[x]) dfs2(hson[x],t);
    for(register int i = head[x];~i;i=nxt[i])
        if(to[i] != f[x] && to[i] != hson[x])
            dfs2(to[i],to[i]);
}

inline int get_lca(int x,int y)
{
    while(top[x] != top[y])
    {
        if(deep[top[x]] < deep[top[y]]) swap(x,y);
        x = f[top[x]];
    }
    if(deep[x] > deep[y]) swap(x,y);
    return x;
}

inline void update(int x,int y)
{
    while(x != y)
    {
        if(deep[x] < deep[y]) swap(x,y);

        int k = vis[x] ? -1 : 1;

        sum += k * w[num[c[x]] + (k > 0)] * v[c[x]];
        num[c[x]] += k;

        vis[x] ^= 1;
        x = f[x];
    }

}

int main()
{
    memset(head,-1,sizeof head);
    memset(ans,-1,sizeof ans);
    read(n); read(m); read(q);
    rep(i,1,m) read(v[i]);
    rep(i,1,n) read(w[i]);
    rep(i,2,n)
    {
        int u,v;
        read(u); read(v);
        add(u,v); add(v,u);
    }

    deep[1] = 1;
    f[1] = 1;
    dfs(1); dfs2(1,1);
    int d = max(1,(int)pow(n,2.0/3)),c1 = 0,c2 = 0,t = 0;
    rep(i,1,n) belong[i] = id[i] / d;
    rep(i,1,n) read(c[i]),lst[i] = c[i];

    rep(i,1,q)
    {
        int x,y,op;
        read(op); read(x); read(y);
        if(op == 0)
        {
            mod[++c1].x = x,mod[c1].y = y,mod[c1].t = i;
            mod[c1].lst = lst[x]; lst[x] = y;
        }
        else
        {
            if(id[x] > id[y]) swap(x,y);
            que[++c2].x = x,que[c2].y = y,que[c2].t = i;
        }
    }

    sort(que + 1,que + 1 + c2,cmp);

    que[0].x = 1,que[0].y = 1;

    rep(i,1,c2)
    {
        while(t < c1 && mod[t + 1].t <= que[i].t)
        {
            ++t;
            if(vis[mod[t].x])
            {
                sum -= w[num[c[mod[t].x]]] * v[c[mod[t].x]];
                --num[c[mod[t].x]]; c[mod[t].x] = mod[t].y;
                ++num[mod[t].y]; sum += w[num[mod[t].y]] * v[mod[t].y];
            }
            c[mod[t].x] = mod[t].y;
        }

        while(t && mod[t].t > que[i].t)
        {
            if(vis[mod[t].x])
            {
                sum -= w[num[c[mod[t].x]]] * v[c[mod[t].x]];
                --num[c[mod[t].x]]; c[mod[t].x] = mod[t].lst;
                ++num[mod[t].lst];sum += w[num[mod[t].lst]] * v[mod[t].lst];
            }
            c[mod[t].x] = mod[t].lst;
            --t;
        }

        update(que[i - 1].x,que[i].x);
        update(que[i - 1].y,que[i].y);

        int z = get_lca(que[i].x,que[i].y);

        ans[que[i].t] = sum + w[num[c[z]]+1] * v[c[z]];
    }

    rep(i,1,q) if(~ans[i]) printf("%lld\n",ans[i]);

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值