题目描述:
中文题面直接上传送门
题目分析:
第一道带修莫队,放礼花~
这道题按照常理来说可以树链剖分+线段树
O
(
n
l
o
g
2
n
)
O(nlog^2n)
O(nlog2n)
用莫队的话得想想怎么维护最小的未出现的自然数
我最开始想的是用树状数组维护每个数前面的自然数的个数,每次修改
l
o
g
n
logn
logn,查询就二分x,看x前面的数的个数是否是x-1,
l
o
g
2
n
log^2n
log2n,总复杂度
O
(
n
5
3
l
o
g
n
+
m
l
o
g
2
n
)
O(n^{\frac 53}logn+mlog^2n)
O(n35logn+mlog2n)
但是莫队的修改数量是肯定大于查询数量的,所以要让修改复杂度降为 O ( 1 ) O(1) O(1),查询就改用分块维护(对权值分块) O ( n ) O(\sqrt n) O(n),总复杂度 O ( n 5 3 + m n ) O(n^{\frac 53}+m\sqrt n) O(n35+mn)
Code:
#include<cstdio>
#include<cctype>
#include<algorithm>
#define maxn 50005
#define S 600
using namespace std;
inline void read(int &a){
char c;while(!isdigit(c=getchar()));
for(a=c-'0';isdigit(c=getchar());a=a*10+c-'0');
}
int n,m,stk[maxn],Tp,bel[maxn],block,a[maxn],b[maxn],A[maxn],B[maxn];
int fa[maxn],dep[maxn],son[maxn],siz[maxn],top[maxn];
int fir[maxn],nxt[maxn<<1],to[maxn<<1],tot;
int ans[maxn];
bool vis[maxn];
struct Query{
int x,y,t,id;
bool operator < (const Query &p)const{return bel[x]==bel[p.x]?bel[y]==bel[p.y]?t<p.t:bel[y]<bel[p.y]:bel[x]<bel[p.x];}
}q[maxn];
struct Change{
int pos,x,y;
}C[maxn];
inline void line(int x,int y){nxt[++tot]=fir[x];fir[x]=tot;to[tot]=y;}
void dfs1(int u){
siz[u]=1;
int cur=Tp;
for(int i=fir[u],v;i;i=nxt[i]) if((v=to[i])!=fa[u]){
fa[v]=u,dep[v]=dep[u]+1;
dfs1(v);siz[u]+=siz[v];
if(siz[v]>siz[son[u]]) son[u]=v;
if(Tp-cur>=S){
++block;
while(Tp>cur) bel[stk[Tp--]]=block;
}
}
stk[++Tp]=u;
}
void dfs2(int u,int tp){
top[u]=tp;
if(son[u]) dfs2(son[u],tp);
for(int i=fir[u];i;i=nxt[i]) if(!top[to[i]]) dfs2(to[i],to[i]);
}
int LCA(int u,int v){
while(top[u]!=top[v]){
if(dep[top[u]]<dep[top[v]]) swap(u,v);
u=fa[top[u]];
}
return dep[u]<dep[v]?u:v;
}
void upd(int x){
if(a[x]>n) return;
if(vis[x]) {if(--A[a[x]]==0) B[a[x]/S]--;}
else {if(A[a[x]]++==0) B[a[x]/S]++;}
vis[x]=!vis[x];
}
void modify(int pos,int x){
if(!vis[pos]) a[pos]=x;
else upd(pos),a[pos]=x,upd(pos);
}
void rev(int u,int v){
while(u!=v){
if(dep[u]<dep[v]) swap(u,v);
upd(u),u=fa[u];
}
}
int solve(){
int i=0;while(B[i]==S) i++;
i*=S;while(A[i]) i++;
return i;
}
int main()
{
int op,x,y,t,qt=0,ct=0,lca;
read(n),read(m);
for(int i=1;i<=n;i++) read(a[i]),b[i]=a[i];
for(int i=1;i<n;i++) read(x),read(y),line(x,y),line(y,x);
dfs1(1);++block;while(Tp) bel[stk[Tp--]]=block;
dfs2(1,1);
for(int i=1;i<=m;i++){
read(op),read(x),read(y);
if(op) q[++qt]=(Query){x,y,ct,qt};
else C[++ct]=(Change){x,b[x],y},b[x]=y;
}
sort(q+1,q+1+qt);
x=q[1].x,y=q[1].x,t=0;
for(int i=1;i<=qt;i++){
while(t<q[i].t) t++,modify(C[t].pos,C[t].y);
while(t>q[i].t) modify(C[t].pos,C[t].x),t--;
rev(x,q[i].x),rev(y,q[i].y),upd(lca=LCA(x=q[i].x,y=q[i].y));
ans[q[i].id]=solve(),upd(lca);
}
for(int i=1;i<=qt;i++) printf("%d\n",ans[i]);
}