感觉关于树的不管是啥都200+行。。。一口老血。。。
首先树上分个块(大概就是BZOJ1086王室联邦的套路,此处应有链接,可惜这道题还在坑里233),然后每次暴力移动点,尤其是关于lca的处理需要很注意(见下图):
(假装有图)
然后这里需要求mex值。对于mex值暴力当然会TLE,于是需要分块。将n个数分成sqrt(n),查询时从头查看哪个块数未满,然后在块中暴力寻找数,复杂度O(sqrt n)。
千万要记得,当一个数修改为大于n时,此数必然不会成为mex数,可以直接跳过,数组开到maxn即可,以免造成MLE。
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxn=200005;
struct edge
{
int to,next;
}e[maxn<<1];
struct query
{
int l,r,id,t;
}q[maxn];
struct change
{
int pre,sub,pos;
}c[maxn];
int n,m,cnt,tot,numblock;
int bcnt,block;
int head[maxn];
int s[maxn],last[maxn],ans[maxn];
int size[maxn],belong[maxn],depth[maxn];
bool inpath[maxn];
int num[maxn],bnum[maxn];
int ff[maxn][22];
bool cmp(query a,query b)
{
return belong[a.l]<belong[b.l]||(belong[a.l]==belong[b.l]&&belong[a.r]<belong[b.r])
||(belong[a.l]==belong[b.l]&&belong[a.r]==belong[b.r]&&a.t<b.t);
}
void insert(int a,int b)
{
static int ecnt=0;
e[++ecnt].to=b;e[ecnt].next=head[a];head[a]=ecnt;
}
void dfs(int x,int fa)
{
static int stack[maxn],top,rear;
int bottom=stack[rear];
stack[++rear]=x;
size[x]=1;
ff[x][0]=fa;
for(int i=head[x];i;i=e[i].next)
if(e[i].to!=fa)
{
depth[e[i].to]=depth[x]+1;
dfs(e[i].to,x);
size[x]+=size[e[i].to];
if(size[x]>=block)
{
++bcnt;
while(stack[rear]!=bottom)
{
int t=stack[rear--];
belong[t]=bcnt;
}
}
}
}
void update(int x)
{
inpath[x]=true;
if(s[x]>n)return;//
if(!num[s[x]])bnum[s[x]/numblock]++;
num[s[x]]++;
}
void downdate(int x)
{
inpath[x]=false;
if(s[x]>n)return;//
if(num[s[x]]==1)bnum[s[x]/numblock]--;
num[s[x]]--;
}
void xorpath(int x,int y)
{
if(depth[x]<depth[y])swap(x,y);
while(depth[x]>depth[y])
{
if(inpath[x])downdate(x);
else update(x);
x=ff[x][0];
}
while(x!=y)
{
if(inpath[x])downdate(x);
else update(x);
x=ff[x][0];
if(inpath[y])downdate(y);
else update(y);
y=ff[y][0];
}
}
int lca(int x,int y)
{
if(depth[x]<depth[y])swap(x,y);
int pos=0,delta=depth[x]-depth[y];
while(delta)
{
if(delta&1)x=ff[x][pos];
pos++;
delta>>=1;
}
if(x==y)return x;
for(int i=20;i>=0;i--)
if(ff[x][i]!=ff[y][i])
x=ff[x][i],y=ff[y][i];
return ff[x][0];
}
void st_chart()
{
for(int i=1;i<=n;i++)
for(int j=1;j<=20;j++)
ff[i][j]=ff[ff[i][j-1]][j-1];
}
int getans()
{
for(int i=0;;i++)if(bnum[i]<numblock)
for(int j=i*numblock;;j++)if(!num[j])
return j;
}
int main()
{
scanf("%d%d",&n,&m);
block=pow(n,2.0/3.0)+1+1e-7;
numblock=sqrt(n)+1+1e-7;
for(int i=1;i<=n;i++)
scanf("%d",s+i),last[i]=s[i];
for(int i=1;i<n;i++)
{
int a,b;
scanf("%d%d",&a,&b);
insert(a,b);
insert(b,a);
}
depth[1]=1;
dfs(1,0);
st_chart();
for(int i=1;i<=m;i++)
{
int a,b,d;
scanf("%d%d%d",&d,&a,&b);
if(d==0)
{
c[++tot].pos=a;
c[tot].pre=last[a];
last[a]=b;
c[tot].sub=b;
}
else
{
q[++cnt].l=a;
q[cnt].r=b;
q[cnt].id=cnt;
q[cnt].t=tot;
}
}
sort(q+1,q+cnt+1,cmp);
int l=1,r=1,t=0;
for(int i=1;i<=cnt;i++)
{
while(t>q[i].t)
{
int pos=c[t].pos;
if(inpath[pos])
{
downdate(pos);
s[pos]=c[t].pre;
update(pos);
}
else
s[pos]=c[t].pre;
t--;
}
while(t<q[i].t)
{
t++;
int pos=c[t].pos;
if(inpath[pos])
{
downdate(pos);
s[pos]=c[t].sub;
update(pos);
}
else
s[pos]=c[t].sub;
}
int LCA=lca(q[i].l,q[i].r);
xorpath(q[i].l,l);
xorpath(q[i].r,r);
l=q[i].l;
r=q[i].r;
update(LCA);
ans[q[i].id]=getans();
downdate(LCA);
}
for(int i=1;i<=cnt;i++)
printf("%d\n",ans[i]);
return 0;
}