您的位置:首页 > 其它

BZOJ 4129 Haruna’s Breakfast 树上莫队

2017-06-24 10:58 309 查看
树上莫队求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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: