1. 程式人生 > >【BZOJ4129】Haruna’s Breakfast(樹上莫隊)

【BZOJ4129】Haruna’s Breakfast(樹上莫隊)

mex 端點 ble Go != gis odi down 分塊

【BZOJ4129】Haruna’s Breakfast(樹上莫隊)

題面

BZOJ

Description

Haruna每天都會給提督做早餐! 這天她發現早飯的食材被調皮的 Shimakaze放到了一棵
樹上,每個結點都有一樣食材,Shimakaze要考驗一下她。
每個食材都有一個美味度,Shimakaze會進行兩種操作:
1、修改某個結點的食材的美味度。
2、對於某條鏈,詢問這條鏈的美味度集合中,最小的未出現的自然數是多少。即mex值。
請你幫幫Haruna吧。

Input

第一行包括兩個整數n,m,代表樹上的結點數(標號為1~n)和操作數。
第二行包括n個整數a1...an,代表每個結點的食材初始的美味度。

接下來n-1行,每行包括兩個整數u,v,代表樹上的一條邊。
接下來m 行,每行包括三個整數
0 u x 代表將結點u的食材的美味度修改為 x。
1 u v 代表詢問以u,v 為端點的鏈的mex值。

Output

對於每次詢問,輸出該鏈的mex值。

Sample Input

10 10

1 0 1 0 2 4 4 0 1 0

1 2

2 3

2 4

2 5

1 6

6 7

2 8

3 9

9 10

0 7 14

1 6 6

0 4 9

1 2 2

1 1 8

1 8 3

0 10 9

1 3 5

0 10 0

0 7 7

Sample Output

0

1

2

2

3

HINT

1<=n<=5*10^4

1<=m<=5*10^4

0<=ai<=10^9

題解

\(mex\)
如果放在序列上做很顯然是裸的莫隊+對數字分塊
放在樹上面就樹上莫隊啊。。。
大於\(n\)的值對答案沒有任何影響,直接丟掉就行了

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue> using namespace std; #define ll long long #define RG register #define MAX 55555 inline int read() { RG int x=0,t=1;RG char ch=getchar(); while((ch<'0'||ch>'9')&&ch!='-')ch=getchar(); if(ch=='-')t=-1,ch=getchar(); while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar(); return x*t; } int n,m,blk; struct Line{int v,next;}e[MAX<<1]; int h[MAX],cnt=1; inline void Add(int u,int v){e[cnt]=(Line){v,h[u]};h[u]=cnt++;} int dfn[MAX],G[MAX],tim,gr,f[16][MAX],S[MAX],top,dep[MAX]; int dfs(int u,int ff) { f[0][u]=ff;dfn[u]=++tim;dep[u]=dep[ff]+1; for(int i=1;i<=15;++i)f[i][u]=f[i-1][f[i-1][u]]; int ret=0; for(int i=h[u];i;i=e[i].next) { int v=e[i].v;if(v==ff)continue; ret+=dfs(v,u); if(ret>=blk){++gr;while(ret--)G[S[top--]]=gr;ret=0;} } S[++top]=u; return ret+1; } struct modify{int x,a,b;}p[MAX]; struct Query{int id,u,v,lb,rb,lm;}q[MAX]; bool operator<(Query a,Query b) { if(a.lb!=b.lb)return a.lb<b.lb; if(a.rb!=b.rb)return a.rb<b.rb; return a.lm<b.lm; } int LCA(int u,int v) { if(dep[u]<dep[v])swap(u,v); for(int i=15;~i;--i)if(dep[f[i][u]]>=dep[v])u=f[i][u]; if(u==v)return u; for(int i=15;~i;--i)if(f[i][u]!=f[i][v])u=f[i][u],v=f[i][v]; return f[0][u]; } int cnt1,cnt2,a[MAX],pre[MAX],nblk; int sum[MAX],sblk[MAX]; bool vis[MAX]; void Change(int x) { if(a[x]>n)return; if(vis[x])--sum[a[x]]?x:--sblk[(a[x])/nblk]; else sum[a[x]]++?x:++sblk[(a[x])/nblk]; vis[x]^=1; } void ModifyLink(int u,int v) { while(u!=v) if(dep[u]<dep[v])Change(v),v=f[0][v]; else Change(u),u=f[0][u]; } int Mex() { for(int i=0;;++i) if(sblk[i]!=nblk) for(int j=0;j<nblk;++j) if(!sum[i*nblk+j])return i*nblk+j; } void ModifyVal(int x,int c) { if(!vis[x])a[x]=c; else Change(x),a[x]=c,Change(x); } int Ans[MAX]; int main() { n=read();m=read();blk=pow(n,0.66);nblk=sqrt(n); for(int i=1;i<=n;++i)a[i]=pre[i]=read(); for(int i=1,u,v;i<n;++i)u=read(),v=read(),Add(u,v),Add(v,u); dfs(1,0); for(int i=1;i<=m;++i) { int opt=read(),u=read(),v=read(); if(opt==0)p[++cnt2]=(modify){u,pre[u],v},pre[u]=v; else { if(dfn[u]>dfn[v])swap(u,v); ++cnt1,q[cnt1]=(Query){cnt1,u,v,G[u],G[v],cnt2}; } } sort(&q[1],&q[cnt1+1]); int lca=LCA(q[1].u,q[1].v),pos=0; while(pos<q[1].lm)++pos,ModifyVal(p[pos].x,p[pos].b); ModifyLink(q[1].u,q[1].v);Change(lca);Ans[q[1].id]=Mex();Change(lca); for(int i=2;i<=cnt1;++i) { while(pos<q[i].lm)++pos,ModifyVal(p[pos].x,p[pos].b); while(pos>q[i].lm)ModifyVal(p[pos].x,p[pos].a),pos--; ModifyLink(q[i-1].u,q[i].u);ModifyLink(q[i-1].v,q[i].v); lca=LCA(q[i].u,q[i].v); Change(lca);Ans[q[i].id]=Mex();Change(lca); } for(int i=1;i<=cnt1;++i)printf("%d\n",Ans[i]); return 0; }

【BZOJ4129】Haruna’s Breakfast(樹上莫隊)