Time:2016.09.08
Author:xiaoyimi
转载注明出处谢谢
思路:
这道题相当于把昨天学的树上莫队和带修莫队融合了一下,顺便加了一个mex(未出现的最小自然数)
那么主要问题就是如何求mex
聪哥给出的思路是对[0,n]权值分块,大于n的权值不用管,因为它们永远不会影响答案(显然)
记录每个块的大小,每一次的移动使得该点权值数量+1或-1,记录这个移动对该点权值所在块大小的影响,也就是说如果这个块中该点权值出现次数为0(1),移动使数量+1(-1),那么块大小-1(+1)
这样的话做到了修改是
O(1)
的
查询时从小到大找到第一个大小不为0的块,然后在该块内部查找最小权值就行了
块的大小是
n23
的
带修莫队复杂度为
O(n53)
注意修改时要修改该点是否在当前已找的集合内,不能因为它的权值>n就不改了
话说我真的不适合用实时倍增求LCA,看来以后还是回归老本行——ST表吧= =
代码:
#include<cstdio>
#include<cmath>
#include<algorithm>
#define M 50005
using namespace std;
int n,m,tot,cnt1,cnt2=1;
int a[M],first[M],last[M],block[M],sum[M],belong[M],siz[M],dfn[M],fa[M][16],dep[M],ans[M];
bool vis[M];
struct edge{
int v,next;
}e[M<<1];
struct query{
int l,r,t,id;
}q[M];
struct update{
int pos,pre,sub;
}c[M];
int in()
{
char ch=getchar();int t=0;
while (ch>'9'||ch<'0') ch=getchar();
while (ch>='0'&&ch<='9') t=(t<<1)+(t<<3)+ch-48,ch=getchar();
return t;
}
void add(int x,int y)
{
e[++tot]=(edge){y,first[x]};first[x]=tot;
e[++tot]=(edge){x,first[y]};first[y]=tot;
}
bool cmp(query a,query b)
{
if (block[a.l]==block[b.l]&&a.r==b.r) return a.t<b.t;
if (block[a.l]==block[b.l]) return dfn[a.r]<dfn[b.r];
return block[a.l]<block[b.l];
}
void dfs(int x)
{
dfn[x]=++dfn[0];
for (int i=first[x];i;i=e[i].next)
if (e[i].v!=fa[x][0])
fa[e[i].v][0]=x,
dep[e[i].v]=dep[x]+1,
dfs(e[i].v);
}
int LCA(int x,int y)
{
if (dep[x]<dep[y]) swap(x,y);
for (int i=15;i>=0;--i)
if (fa[x][i]&&dep[fa[x][i]]>=dep[y])
x=fa[x][i];
if (x==y) return x;
for (int i=15;i>=0;--i)
if (fa[x][i]&&fa[x][i]!=fa[y][i])
x=fa[x][i],y=fa[y][i];
return fa[x][0];
}
void Point(int x)
{
if (a[x]>n) {vis[x]^=1;return;}
if (vis[x]) siz[belong[a[x]]]+=(--sum[a[x]]==0);
else siz[belong[a[x]]]-=(++sum[a[x]]==1);
vis[x]^=1;
}
void Path(int x,int y)
{
if (dep[x]<dep[y]) swap(x,y);
for (;dep[x]>dep[y];x=fa[x][0]) Point(x);
for (;x!=y;x=fa[x][0],y=fa[y][0]) Point(x),Point(y);
}
int cal()
{
int i,j,t=sqrt(n+1);
for (i=0;i<=t;++i)
if (siz[i]) break;
for (j=i*t;j<(i+1)*t;++j)
if (!sum[j]) return j;
}
main()
{
n=in();m=in();
int tt=pow(n,2.0/3.0);
for (int i=1;i<=n;++i)
last[i]=a[i]=in();
for (int i=1;i<n;++i) add(in(),in());
dfs(1);
for (int i=1;i<=n;++i) block[i]=(dfn[i]+1)/tt;
for (int i=1;i<=15;++i)
for (int j=1;j<=n;++j)
fa[j][i]=fa[fa[j][i-1]][i-1];
tt=sqrt(n+1);
for (int i=0;i<=n;++i)
belong[i]=i/tt,
++siz[belong[i]];
int x,y;
for (int i=1;i<=m;++i)
if (in())
q[++cnt1]=(query){in(),in(),cnt2,cnt1};
else
x=in(),y=in(),
c[++cnt2]=(update){x,last[x],y},last[x]=y;
sort(q+1,q+cnt1,cmp);
int T=1,L=1,R=1;Point(1);
for (int i=1;i<=cnt1;++i)
{
for (int j=T+1;j<=q[i].t;++j)
if (vis[c[j].pos])
{
Point(c[j].pos);
a[c[j].pos]=c[j].sub;
Point(c[j].pos);
}
else a[c[j].pos]=c[j].sub;
for (int j=T;j>q[i].t;--j)
if (vis[c[j].pos])
{
Point(c[j].pos);
a[c[j].pos]=c[j].pre;
Point(c[j].pos);
}
else a[c[j].pos]=c[j].pre;
Path(q[i].l,L);Path(q[i].r,R);
Point(LCA(L,R));
Point(LCA(q[i].l,q[i].r));
ans[q[i].id]=cal();
T=q[i].t;L=q[i].l;R=q[i].r;
}
for (int i=1;i<=cnt1;++i) printf("%d\n",ans[i]);
}