zoukankan      html  css  js  c++  java
  • 【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
    ",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
    ", ans[i]);
    }
  • 相关阅读:
    高斯消元学习
    HDU 4596 Yet another end of the world(解一阶不定方程)
    Codeforces Round #318 div2
    HDU 4463 Outlets(一条边固定的最小生成树)
    HDU 4458 Shoot the Airplane(计算几何 判断点是否在n边形内)
    HDU 4112 Break the Chocolate(简单的数学推导)
    HDU 4111 Alice and Bob (博弈)
    POJ 2481 Cows(线段树单点更新)
    HDU 4288 Coder(STL水过)
    zoj 2563 Long Dominoes
  • 原文地址:https://www.cnblogs.com/candy99/p/6572644.html
Copyright © 2011-2022 走看看