BZOJ4129 : Haruna’s Breakfast

树上带修改莫队算法,对于维护mex值,可以使用修改$O(1)$,查询$O(\sqrt{n})$的权值分块,总时间复杂度为$O(n^\frac{5}{3})$。

 

#include<cstdio>
#include<algorithm>
#define N 50010
#define K 15
using namespace std;
inline void read(int&a){char c;while(!(((c=getchar())>='0')&&(c<='9')));a=c-'0';while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';}
struct Que{int l,r,t,z;}ask[N];
int ans[N];
int n,m,q,i,j,k,x,y,z,f[N][16],d[N],B,nl,nr,l,r,vis[N],C[N],c[N];
int T,mx[N],my[N],op[N];
int st[N],en[N],dfn[N<<1],pos[N<<1],post,g[N],v[N<<1],nxt[N<<1],ed,que[50][50],fin[50][50];
int ap[N],h[N],full[N],now[N];
inline void add(int x,int y){v[++ed]=y;nxt[ed]=g[x];g[x]=ed;}
void dfs(int x,int pre){
  dfn[st[x]=++post]=x;
  int i=1;
  for(f[x][0]=pre;i<=K;i++)f[x][i]=f[f[x][i-1]][i-1];
  for(i=g[x];i;i=nxt[i])if(v[i]!=pre)d[v[i]]=d[x]+1,dfs(v[i],x);
  dfn[en[x]=++post]=x;
}
inline int lca(int x,int y){
  if(x==y)return x;
  if(d[x]<d[y])swap(x,y);
  for(int i=K;~i;i--)if(d[f[x][i]]>=d[y])x=f[x][i];
  if(x==y)return x;
  for(int i=K;~i;i--)if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i];
  return f[x][0];
}
inline void addq(int x,int y,int z){
  v[++ed]=z;nxt[ed]=0;
  if(!que[x][y])que[x][y]=ed;else nxt[fin[x][y]]=ed;
  fin[x][y]=ed;
}
inline void deal(int x){
  if(c[x]<=n){
    if(vis[x]){
      ap[c[x]]--;
      if(!ap[c[x]])now[pos[c[x]]]--;
    }else{
      if(!ap[c[x]])now[pos[c[x]]]++;
      ap[c[x]]++;
    }
  }
  vis[x]^=1;
}
inline int askmex(){for(int i=0;;i++)if(full[i]>now[i])for(int j=h[i];;j++)if(!ap[j])return j;}
int main(){
  read(n);read(q);
  for(i=1;i<=n;i++)read(C[i]);
  for(i=1;i<n;i++)read(x),read(y),add(x,y),add(y,x);
  dfs(d[1]=1,ed=0);
  while(B*B*B<post)B++;B*=B;
  for(i=1;i<=post;i++)pos[i]=(i-1)/B+1;m=pos[post];
  for(i=1;i<=q;i++){
    read(op[i]);read(x);read(y);
    if(!op[i])mx[++T]=x,my[T]=y;
    else{
      if(st[x]>st[y])swap(x,y);
      z=lca(x,y);
      if(z==x)nl=st[x],nr=st[y];else nl=en[x],nr=st[y];
      ask[i].t=T;
      ask[i].l=nl;ask[i].r=nr;
      if(z!=x)ask[i].z=z;
      addq(pos[nl],pos[nr],i);
    }
  }
  for(B=1;B*B<=n;B++);
  for(i=1;i<=n;i++)pos[i]=(i-1)/B+1;
  for(i=0;i<=n;i++)full[pos[i]]++;
  for(i=n;i;i--)h[pos[i]]=i;
  for(i=1;i<=m;i++)for(j=i;j<=m;j++)if(que[i][j]){
    for(k=0;k<=n;k++)c[k]=C[k],vis[k]=ap[k]=0;
    for(k=0;k<=pos[n];k++)now[k]=0;
    T=1;l=(i-1)*B+1;r=l-1;
    for(k=que[i][j];k;k=nxt[k]){
      if(r<ask[v[k]].r){for(r++;r<=ask[v[k]].r;r++)deal(dfn[r]);r--;}
      if(r>ask[v[k]].r)for(;r>ask[v[k]].r;r--)deal(dfn[r]);
      if(l<ask[v[k]].l)for(;l<ask[v[k]].l;l++)deal(dfn[l]);
      else if(l>ask[v[k]].l){for(l--;l>=ask[v[k]].l;l--)deal(dfn[l]);l++;}
      while(T<=ask[v[k]].t){
        bool flag=(ask[v[k]].l<=st[mx[T]]&&st[mx[T]]<=ask[v[k]].r)^(ask[v[k]].l<=en[mx[T]]&&en[mx[T]]<=ask[v[k]].r);
        if(flag)deal(mx[T]);
        c[mx[T]]=my[T];
        if(flag)deal(mx[T]);
        T++;
      }
      if(ask[v[k]].z)deal(ask[v[k]].z);
      ans[v[k]]=askmex();
      if(ask[v[k]].z)deal(ask[v[k]].z);
    }
  }
  for(i=1;i<=q;i++)if(op[i])printf("%d\n",ans[i]);
  return 0;
}

  

posted @ 2015-09-05 00:04  Claris  阅读(552)  评论(0编辑  收藏  举报