BZOJ 4129 Haruna’s Breakfast 树上莫队

树上莫队求mex,关键点:I.树上莫队(废话)II.树状数组+二分 log^2 求mex 

树上莫队的时间复杂度一定是O(n1.5)的证明 I.右端点dfs序 II.左端点均摊(卡的话是一个近似二次函数的东西,会随着卡你的地方增多而卡的程度减小)

#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<iostream>
#define N 18
#define MAXN 51000
using namespace std;
int pos[MAXN+10],id[MAXN+10],a[MAXN+10],b[MAXN+10],len,n,m,f[MAXN+10][N+10],size,d[MAXN+10],had[MAXN+10];
bool belong[MAXN+10];
struct Q
{
   int l,r,time,ans,id;
}q[MAXN+10];
struct T
{
   int a,b,pos;
}t[MAXN+10];
struct Tree
{
   int to,next; 
}c[MAXN<<2];
int head[MAXN+10],sz,cause;
inline void update(int x,int i)
{
   if(x==0)return;
   while(x<MAXN)
   {
      b[x]+=i;
      x+=x&(-x);
   }
}
inline int sum(int x)
{
   int ret=0;
   while(x>0)
   {
     ret+=b[x];
     x-=x&(-x);
   }
   return ret;
}
inline void add(int x,int y)
{
   c[++sz].to=y;
   c[sz].next=head[x];
   head[x]=sz;
   c[++sz].to=x;
   c[sz].next=head[y];
   head[y]=sz;
}
int l,r,now;
void dfs(int x)
{
   id[x]=++cause;
   d[x]=d[f[x][0]]+1;
   for(int i=1;i<N;i++)
    f[x][i]=f[f[x][i-1]][i-1];
   for(int i=head[x];i;i=c[i].next)
   if(c[i].to!=f[x][0])
   {
     f[c[i].to][0]=x;
     dfs(c[i].to);
   }
}
int comp(const Q aa,const Q bb)
{
   return pos[id[aa.l]]<pos[id[bb.l]]||(pos[id[aa.l]]==pos[id[bb.l]]&&id[aa.r]<id[bb.r]);
}
int end_comp(const Q aa,const Q bb)
{
   return aa.id<bb.id;
}
void pre()
{
   scanf("%d%d",&n,&m);
   len=(int)(sqrt(n+0.5));
   for(int i=1;i<=n;i++)
   {
    scanf("%d",&a[i]);
    pos[i]=(i-1)/len+1;
   }
   for(int i=1;i<n;i++)
   {
     int x,y;
     scanf("%d%d",&x,&y);
     add(x,y);
   }
   dfs(1);
   for(int i=1;i<=m;i++)
   {
     int opt,x,y;
     scanf("%d%d%d",&opt,&x,&y);
     if(opt==0)
     {
        now++;
        t[now].a=a[x];
        t[now].b=y;
        t[now].pos=x;
        a[x]=y;
     }
     else
     {
        q[++size].l=x;
        q[size].r=y;
        q[size].time=now;
        q[size].id=size;
     }
   }
   sort(q+1,q+size+1,comp);
   l=r=1;
   belong[1]=1;
   if(a[1]<MAXN)had[a[1]]=1;
   if(a[1]>=MAXN||a[1]==0)return;
   update(a[1],1);
}
int Lca(int x,int y)
{
   if(d[x]<d[y]) x^=y^=x^=y;
   int k=d[x]-d[y];
   for(int i=0;i<N;i++)
     if((1<<i)&k)
      x=f[x][i];
   if(x==y)
   {
     return x;
   }
   for(int i=N-1;i>=0;i--)
   if(f[x][i]!=f[y][i])
   {
     x=f[x][i];
     y=f[y][i];
   }
   return f[x][0];
}
inline void via(int x)
{
   belong[id[x]]^=1;
   if(a[x]>=MAXN)return;
   if(belong[id[x]])
   {
     had[a[x]]++;
     if(a[x]==0)return;
     if(had[a[x]]==1)
      update(a[x],1);
   }
   else
   {
     had[a[x]]--;
     if(a[x]==0)return;
     if(had[a[x]]==0)
      update(a[x],-1);
   }
}
inline void come(int x)
{
   if(!x)return;
   a[t[x].pos]=t[x].b;
   if(belong[id[t[x].pos]])
   {
     if(t[x].a<MAXN)
     {
        had[t[x].a]--;
        if(t[x].a!=0&&had[t[x].a]==0)
         update(t[x].a,-1);
     }
     if(t[x].b<MAXN)
     {
        had[t[x].b]++;
        if(t[x].b!=0&&had[t[x].b]==1)
         update(t[x].b,1);
     }
   }
}
inline void go(int x)
{
   if(!x)return;
   a[t[x].pos]=t[x].a;
   if(belong[id[t[x].pos]])
   {
     if(t[x].b<MAXN)
     {
        had[t[x].b]--;
        if(t[x].b!=0&&had[t[x].b]==0)
         update(t[x].b,-1);
     }
     if(t[x].a<MAXN)
     {
        had[t[x].a]++;
        if(t[x].a!=0&&had[t[x].a]==1)
         update(t[x].a,1);
     }
   }
}
inline int answer()
{
   if(had[0]==0)return 0;
   int z=1,y=MAXN-1,ans=0;
   while(z<=y)
   {
      int mid=(z+y)>>1;
      int ques=sum(mid);
      if(ques<mid)
       ans=mid,y=mid-1;
      else
       z=mid+1;
   }
   return ans;
}
void work()
{
   for(int i=1;i<=size;i++)
   {
      while(now<q[i].time)come(++now);
      while(now>q[i].time)go(now--);
      int lca1=Lca(q[i].l,q[i].r);
      int lca2=Lca(l,r);
      int lca3=Lca(q[i].l,l);
      int lca4=Lca(q[i].r,r);
      while(l!=lca3)
      {
         via(l);
         l=f[l][0];
      }
      l=q[i].l;
      while(l!=lca3)
      {
         via(l);
         l=f[l][0];
      }
      l=q[i].l;
      while(r!=lca4)
      {
         via(r);
         r=f[r][0];
      }
      r=q[i].r;
      while(r!=lca4)
      {
         via(r);
         r=f[r][0];
      }
      r=q[i].r;
      if(lca1!=lca2)
      {
          via(lca1);
          via(lca2);              
      }
      q[i].ans=answer();
   }
}
void print()
{
   sort(q+1,q+size+1,end_comp);
   for(int i=1;i<=size;i++)
    printf("%d\n",q[i].ans);
}
int main()
{
    pre();
    work();
    print();
    return 0;
} 

 

posted @ 2017-06-24 10:58  TS_Hugh  阅读(238)  评论(0编辑  收藏  举报