【WC2013】糖果公园 [树上莫队]

题意:

一棵树,修改一个点的颜色,询问两点路径上每种颜色的权值$val[c]$*出现次数的权值$cou[w[c]]$的和


sro VFK 

树上莫队

按照王室联邦的方法分块,块的大小直径个数有保证,并不需要连通

和带修改莫队一样按照$(pos[u],pos[v],tim)$排序

维护$u,v,cur$三个点,以及每个节点的访问状态$vis[]$,每种颜色出现次数$cou[]$,当前答案$now$

如何移动?

时间移动和序列上一样

$u,v$移动到$u,v'$

$Path(u,v)=Path(u,root) \oplus Path(v,root) \oplus lca(u,v)$

先不管$lca$,令$T(u,v)=Path(u,root) \oplus Path(v,root)$

$T(u,v')=Path(u,root) \oplus Path(v',root)$

经计算$T(u,v')=T(u,v) \oplus T(v,v')$

画一下图很好理解

所以移动的时候我们只要更新$v$到$v'$路径上除去$lca$的所有点就可以了,最后对于每个询问额外把$lca(u,v)$加上

 

分块大小貌似稍小一点比较好

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
typedef long long ll;
const int N=1e5+5;
inline int read(){
    char c=getchar();int x=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}

int n,k,Q,a[N],t[N],op,x,y, val[N];
ll w[N];

struct edge{int v,ne;} e[N<<1];
int cnt,h[N];
inline void ins(int u,int v){
    e[++cnt]=(edge){v,h[u]}; h[u]=cnt;
    e[++cnt]=(edge){u,h[v]}; h[v]=cnt;
}
int block,m,pos[N];
int st[N],top;
void dfs(int u,int fa){
    int bot=top;
    for(int i=h[u];i;i=e[i].ne) if(e[i].v!=fa){
        dfs(e[i].v, u);
        if(top-bot>=block){
            m++;
            while(top!=bot) pos[st[top--]]=m;
        }
    }
    st[++top]=u;
}

int fa[N][20], deep[N];
void dfs(int u){
    for(int i=1; (1<<i)<=deep[u]; i++)
        fa[u][i]=fa[ fa[u][i-1] ][i-1];
    for(int i=h[u];i;i=e[i].ne)
        if(e[i].v!=fa[u][0]){
            deep[ e[i].v ]=deep[u]+1;
            fa[ e[i].v ][0]=u;
            dfs(e[i].v);
        }
}
inline int lca(int x,int y){
    if(deep[x]<deep[y]) swap(x, y);
    int bin=deep[x]-deep[y];
    for(int i=0;i<17;i++) if((1<<i)&bin) x=fa[x][i];
    for(int i=17;i>=0;i--) 
        if(fa[x][i]!=fa[y][i]) x=fa[x][i], y=fa[y][i];
    return x==y ? x : fa[x][0];
}

struct cmeow{int u,next,last;} cq[N];
struct meow{
    int u,v,tim,id;
    bool operator <(const meow &a) const {
        return pos[u]==pos[a.u] ? (pos[v]==pos[a.v] ? tim<a.tim : pos[v]<pos[a.v]) : pos[u]<pos[a.u];
    }
}q[N];
int p,tim,u,v,cur; ll now,ans[N];
int vis[N], cou[N]; 
inline void cha(int u,int d){ 
    int &c=a[u];
    if(vis[u]){
        now-= w[cou[c]] * val[c]; now-= w[cou[d]] * val[d];
        cou[c]--; cou[d]++;
        now+= w[cou[c]] * val[c]; now+= w[cou[d]] * val[d];
    }
    c=d;
}
inline void Xor(int u){
    int c=a[u];
    now-= w[cou[c]] * val[c];
    vis[u] ? cou[c]-- : cou[c]++;  vis[u]^=1;
    now+= w[cou[c]] * val[c];
}
void move(int x,int y){ 
    if(deep[x]<deep[y]) swap(x, y);
    while(deep[x]>deep[y]) Xor(x), x=fa[x][0];// printf("%d %lld\n",x,now);
    while(x!=y) Xor(x), Xor(y), x=fa[x][0], y=fa[y][0];
}
void modui(){
    u=1; v=1;
    for(int i=1;i<=p;i++){
        while(cur<q[i].tim) cur++, cha(cq[cur].u, cq[cur].next);
        while(cur>q[i].tim) cha(cq[cur].u, cq[cur].last), cur--;
        if(u!=q[i].u) move(u, q[i].u), u=q[i].u;
        if(v!=q[i].v) move(v, q[i].v), v=q[i].v;

        int anc=lca(u, v);
        Xor(anc); ans[q[i].id]= now; Xor(anc);
    }
}
int main(){
    freopen("in","r",stdin);
    n=read(); k=read(); Q=read();
    for(int i=1;i<=k;i++) val[i]=read();
    for(int i=1;i<=n;i++) w[i]=read()+w[i-1];
    for(int i=1;i<n ;i++) ins(read(), read() );
    for(int i=1;i<=n;i++) a[i]=t[i]=read();

    block=pow(n,(double)1.9/3);
    dfs(1, 0);
    while(top) pos[st[top--]]=m;
    dfs(1);

    for(int i=1;i<=Q;i++){
        op=read(); x=read(); y=read();
        if(op) p++,q[p]=(meow){x,y,tim,p};
        else tim++,cq[tim]=(cmeow){x,y,t[x]}, t[x]=y;
    }
    sort(q+1, q+1+p);
    modui();
    for(int i=1;i<=p;i++) printf("%lld\n", ans[i]);
}

 

posted @ 2017-03-18 11:50  Candy?  阅读(264)  评论(0编辑  收藏  举报