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
原文地址:https://www.cnblogs.com/iamCYY/p/4719913.html