• BZOJ3052: [wc2013]糖果公园


    http://www.lydsy.com/JudgeOnline/problem.php?id=3052

      树上的带修改莫队算法。

      按左端点所在块为第一关键字,右端点所在块为第二关键字,时间为第三关键字,排序。然后进行树上莫队,每次询问经过修改或逆修改来使时间倒流或前进。

      复杂度证明:

        设block_num为块数,block_size为块的大小,则有block_num×block_size=n,在证明中我们假设n,q同阶。

        设块对(block_i,block_j),易知这样的块对不会超过block_num2个。

        对于块对内的操作:我们考虑总复杂度,左端点共移动至多O(q×block_size),右端点亦是。时间共移动至多O(block_num2×q)。故这一部分的复杂度为O(n×(block_size+block_num2))。

        对于块与块之间的操作,不超过block_num2次:左端第移动一次,最多O(n),右端点亦是如此。时间最多移动O(q)=O(n)。故这一部分复杂度为O(block_num2×n)。

        故总复杂度为O(n×(block_size+block_num2))。

      可以证明当block_size=n2/3时,block_num=n1/3,复杂度最优,为O(n5/3)。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long int64;
    const int maxn=100015,maxe=200015,maxm=100015,maxq=100015,maxk=20;
    struct Tmodify{int x,v;}M[maxq];
    struct Tquery{int i,u,v,t;}Q[maxq];
    int tot,now[maxn],pre[maxe],son[maxe];
    int n,m,q,lim,tim,ask,v[maxm],w[maxn],c[maxn];
    inline void connect(int u,int v){pre[++tot]=now[u];now[u]=tot;son[tot]=v;}
    inline void read(int &x){
        char c;
        for (c=getchar();c<'0'||c>'9';c=getchar());
        for (x=0;c>='0'&&c<='9';c=getchar()) x=x*10+c-'0';
    }
    void init(){
        read(n);read(m);read(q);lim=log2(n);
        for (int i=1;i<=m;++i) read(v[i]);
        for (int i=1;i<=n;++i) read(w[i]);
        for (int i=1,u,v;i<=n-1;++i){read(u);read(v);connect(u,v);connect(v,u);}
        for (int i=1;i<=n;++i) read(c[i]);
        for (int t,x,y,i=1;i<=q;++i){
            read(t);read(x);read(y);
            switch (t){
                case 0:M[++tim]=(Tmodify){x,y};break;
                case 1:Q[++ask]=(Tquery){ask,x,y,tim};break;
            }
        }
    }
    int dep[maxn],anc[maxn][maxk];
    void get_anc(int u,int f){
        anc[u][0]=f;dep[u]=dep[f]+1;
        for (int k=1;k<=lim;++k) anc[u][k]=anc[anc[u][k-1]][k-1];
        for (int p=now[u];p;p=pre[p]) if (son[p]!=f) get_anc(son[p],u);
    }
    int siz,cnt,top,stk[maxn],bel[maxn];
    void get_block(int u,int f){
        for (int bot=top,p=now[u];p;p=pre[p])
            if (son[p]!=f){
                get_block(son[p],u);
                if (top-bot>=siz) for(++cnt;top!=bot;bel[stk[top--]]=cnt);
            }
        stk[++top]=u;
    }
    void prepare(){
        siz=(int)pow(n,0.6);
        get_anc(1,0);get_block(1,0);
        for (int i=1;i<=top;++i) bel[stk[i]]=cnt;
        for (int i=1;i<=ask;++i) if (bel[Q[i].u]>bel[Q[i].v]) swap(Q[i].u,Q[i].v);
    }
    inline bool cmp(const Tquery &x,const Tquery &y){
        if (bel[x.u]!=bel[y.u]) return bel[x.u]<bel[y.u];
        else if (bel[x.v]!=bel[y.v]) return bel[x.v]<bel[y.v];
        else return x.t<y.t;
    }
    bool exist[maxn];
    int64 res,ans[maxq];int sum[maxm];
    inline void xor_node(int x){    
        if (exist[x]) res-=1ll*v[c[x]]*w[sum[c[x]]--];
        else res+=1ll*v[c[x]]*w[++sum[c[x]]];
        exist[x]^=1;
    }
    inline void xor_path(int u,int v){
        if (dep[u]<dep[v]) swap(u,v);
        while (dep[u]!=dep[v]){xor_node(u);u=anc[u][0];}
        while (u!=v){xor_node(u);xor_node(v);u=anc[u][0];v=anc[v][0];}
    }
    inline void modify(int k){
        int x=M[k].x,ever=c[x],now=M[k].v;
        if (exist[x]){
            res-=1ll*v[ever]*w[sum[ever]--];
            res+=1ll*v[now]*w[++sum[now]];
        }
        swap(c[x],M[k].v);
    }
    inline void move_time(int ever,int now){
        for (int i=ever+1;i<=now;++i) modify(i);
        for (int i=ever;i>=now+1;--i) modify(i);
    }
    inline int lca(int u,int v){
        if (dep[u]<dep[v]) swap(u,v);
        for (int i=0,h=dep[u]-dep[v];h;++i,h>>=1) if (h&1) u=anc[u][i];
        for (int k=lim;k>=0;--k) if (anc[u][k]!=anc[v][k]){u=anc[u][k];v=anc[v][k];}
        return u==v?u:anc[u][0];
    }
    inline void solve(int k){
        xor_path(Q[k-1].u,Q[k].u);
        xor_path(Q[k-1].v,Q[k].v);
        move_time(Q[k-1].t,Q[k].t);
        int x=lca(Q[k].u,Q[k].v);
        xor_node(x);ans[Q[k].i]=res;xor_node(x);
    }
    void work(){
        prepare();sort(Q+1,Q+ask+1,cmp);
        Q[0]=(Tquery){0,1,1,0};for (int i=1;i<=ask;++i) solve(i);
        for (int i=1;i<=ask;++i) printf("%lld
    ",ans[i]);
    }
    int main(){
        init();
        work();
        return 0;
    }
    my code
  • 相关阅读:
    题解报告:hdu1995汉诺塔V(递推dp)
    黑色CSS3立体动画菜单
    jQuery计算器插件
    CSS3动画库animate.css
    缩略图悬浮效果的jQuery焦点图
    CSS伪元素实现的3D按钮
    CSS3 3D旋转按钮对话框
    jQuery仿Android锁屏图案应用
    jQuery横向图片手风琴
    jQuery滑动杆打分插件
  • 原文地址:https://www.cnblogs.com/iamCYY/p/4719913.html
Copyright © 2020-2023  润新知