首页 > 代码库 > BZOJ4129(树上带修莫队)

BZOJ4129(树上带修莫队)

树上莫队的基本思路是把树按dfs序分块,然后先按x所在块从小到大排序,再按y所在块从小到大排序,处理询问即可。

这道题带修改,再加一个时间维即可。

时间复杂度据说是$n^{\frac53}$,不知道是为什么。

(块大小改成3也过了什么鬼..)

#include <cstdio>
#include <algorithm>
using namespace std;

const int N=50005,M=100005,B=1357,T=223;
int n,m,e,x,y,t,tp,op,tt,t1,t2,a[N],_a[N],bl[N],st[N],hd[N],nx[M],to[M],d[N],a1[N],g[N],h[N],v[N],f[N][16];
struct nd {
    int x,y,t,id;
    bool operator < (const nd &r) const {
        return bl[x]==bl[r.x]?bl[y]==bl[r.y]?t<r.t:bl[y]<bl[r.y]:bl[x]<bl[r.x];
    }
}b[N];
struct nd2 {
    int x,y,t,ls;
    bool operator < (const nd2 &r) const {return t<r.t;}
}c[N];
void ad(int x,int y) {to[++e]=y,nx[e]=hd[x],hd[x]=e;}

void dfs(int x) {
    st[++tp]=x;
    if(tp==B) {tt++; while(tp) bl[st[tp--]]=tt;}
    for(int i=hd[x];i;i=nx[i]) if(!d[to[i]]) d[to[i]]=d[x]+1,f[to[i]][0]=x,dfs(to[i]);
}
int lca(int x,int y) {
    if(d[x]<d[y]) swap(x,y);
    for(int i=15;~i;i--) if(d[f[x][i]]>=d[y]) x=f[x][i];
    if(x==y) return x;
    for(int i=15;~i;i--) if(f[x][i]^f[y][i]) x=f[x][i],y=f[y][i];
    return f[x][0];
}

void up(int x) {
    if(x>n) return;
    if(!g[x]++) h[x/T]++;
}
void _up(int x) {
    if(x>n) return;
    if(!--g[x]) h[x/T]--;
}
void rv(int x) {
    v[x]^=1;
    if(a[x]>n) return;
    if(v[x]) up(a[x]); else _up(a[x]);
}
void gai(int x,int y) {if(v[x]) rv(x),a[x]=y,rv(x); else a[x]=y;}
void rev(int x,int y) {
    while(x^y) {
        if(d[x]<d[y]) swap(x,y);
        rv(x),x=f[x][0];
    }
}
int qry() {
    int r;
    for(int i=0;;i++) if(h[i]!=T) {r=i; break;}
    for(int i=r*T;i<(r+1)*T;i++) if(!g[i]) return i;
    return 233;
}

int main() {
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]),_a[i]=a[i];
    for(int i=1;i<n;i++) scanf("%d%d",&x,&y),ad(x,y),ad(y,x);
    d[1]=1,dfs(1),tt++;
    while(tp) bl[st[tp--]]=tt;
    for(int j=1;j<16;j++)
    for(int i=1;i<=n;i++)
        f[i][j]=f[f[i][j-1]][j-1];
    for(int i=1;i<=m;i++) {
        scanf("%d%d%d",&op,&x,&y);
        if(op) b[++t1].x=x,b[t1].y=y,b[t1].t=i,b[t1].id=t1;
        else c[++t2].x=x,c[t2].y=y,c[t2].t=i,c[t2].ls=_a[x],_a[x]=y;
    }
    sort(b+1,b+1+t1),sort(c+1,c+1+t2);
    for(int i=1,j=1,l=1,r=1;i<=t1;i++) {
        while(t<b[i].t) {
            t++;
            while(j<=t2&&c[j].t==t) gai(c[j].x,c[j].y),j++;
        }
        while(t>b[i].t) {
            while(j>1&&c[j-1].t==t) j--,gai(c[j].x,c[j].ls);
            t--;
        }
        int k=lca(b[i].x,b[i].y);
        rev(b[i].x,l),rev(b[i].y,r),rv(k),a1[b[i].id]=qry(),rv(k),l=b[i].x,r=b[i].y;
    }
    for(int i=1;i<=t1;i++) printf("%d\n",a1[i]);
    return 0;
}

BZOJ4129(树上带修莫队)