您的位置:首页 > 其它

[BZOJ]4129: Haruna’s Breakfast 树上带修改莫队+分块

2017-08-07 13:49 323 查看
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值。

题解:

mex问题我们可以容易对数字进行分块+莫队从而解决,详情见BZOJ3585(权限题)。到了树上,我们可以考虑用树上莫队,又由于有修改,我们用带修改莫队。做法都差不多,我是参考neither_nor的代码的。有几个地方要注意一下:1、树上的分块,每块的大小是n23,我也不知道为什么……2、从(L,R)到(X,Y)的处理,看一下代码,脑补一下就差不多了。

代码:

#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=50010;
struct Edge{int y,next;}e[maxn*2];
int last[maxn],len=0;
void ins(int x,int y)
{
int t=++len;
e[t].y=y;e[t].next=last[x];last[x]=t;
}
int dep[maxn],fa[maxn][18];
int sta[maxn],top=0,bl[maxn],MX,cnt=0;
int n,m,belong[maxn],c[maxn],block[250],l[250],r[250],vis[maxn],a[maxn];
void dfs(int x)
{
dep[x]=dep[fa[x][0]]+1;
for(int i=1;(1<<i)<=dep[x];i++)fa[x][i]=fa[fa[x][i-1]][i-1];
int now=top;
for(int i=last[x];i;i=e[i].next)
{
int y=e[i].y;
if(y==fa[x][0])continue;
fa[y][0]=x;dfs(y);
if(top-now>MX)
{
cnt++;
while(top>now)bl[sta[top--]]=cnt;
}
}
sta[++top]=x;
if(x==1)
{
cnt++;
while(top)bl[sta[top--]]=cnt;
}
}
int LCA(int x,int y)
{
if(dep[x]<dep[y])swap(x,y);//x jump
for(int i=17;i>=0;i--)
if((1<<i)<=dep[x]-dep[y])x=fa[x][i];
if(x==y)return x;
for(int i=17;i>=0;i--)
if(dep[x]>=(1<<i)&&fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i];
return fa[x][0];
}
void add(int x)
{
if(a[x]>n)return;
c[a[x]]++;
if(c[a[x]]==1)block[belong[a[x]]]++;
}
void del(int x)
{
if(a[x]>n)return;
c[a[x]]--;
if(!c[a[x]])block[belong[a[x]]]--;
}
void change(int x,int y)
{
if(vis[x])del(x),a[x]=y,add(x);
else a[x]=y;
}
void rev(int x)
{
if(vis[x])vis[x]=0,del(x);
else vis[x]=1,add(x);
}
int calc()
{
if(!c[0])return 0;
int i;
for(i=1;i<=belong
;i++)
if(block[i]!=r[i]-l[i]+1)break;
for(int j=l[i];j<=r[i];j++)
if(!c[j])return j;
}
struct Modify{int x,y,pre;}A[maxn];
struct Query{int x,y,time,id;}B[maxn];
bool cmp(Query a,Query b)
{
if(bl[a.x]!=bl[b.x])return bl[a.x]<bl[b.x];
if(bl[a.y]!=bl[b.y])return bl[a.y]<bl[b.y];
return a.time<b.time;
}
int la=0,lb=0,ans[maxn],yl[maxn];
int main()
{
memset(block,0,sizeof(block));
memset(c,0,sizeof(c));
scanf("%d%d",&n,&m);
MX=(int)pow(1.0*n*n,1.0/3);
for(int i=1;i<=n;i++)scanf("%d",&a[i]),yl[i]=a[i];
int sq=(int)sqrt(n);
for(int i=1;i<=n;i++)//对数字进行分块
{
belong[i]=(i-1)/sq+1;
int w=belong[i];
if(!l[w])l[w]=i;
r[w]=i;
}
for(int i=1;i<n;i++
107b6
)
{
int u,v;
scanf("%d%d",&u,&v);
ins(u,v);ins(v,u);
}
dfs(1);
for(int i=1;i<=m;i++)
{
int op,x,y;
scanf("%d%d%d",&op,&x,&y);
if(op==0)
{
A[++la].x=x;A[la].y=y;
A[la].pre=a[x];
a[x]=y;
}
else
{
B[++lb].x=x;B[lb].y=y;
B[lb].time=la;B[lb].id=lb;
}
}
sort(B+1,B+1+lb,cmp);
for(int i=1;i<=n;i++)a[i]=yl[i];
int L=1,R=1;B[0].time=0;
for(int i=1;i<=lb;i++)
{
int l1=LCA(B[i].x,L);
int l2=LCA(B[i].y,R);
for(int x=L;x!=l1;x=fa[x][0])rev(x);
for(int x=B[i].x;x!=l1;x=fa[x][0])rev(x);
for(int x=R;x!=l2;x=fa[x][0])rev(x);
for(int x=B[i].y;x!=l2;x=fa[x][0])rev(x);
L=B[i].x;R=B[i].y;
int l=LCA(L,R);
rev(l);
for(int j=B[i-1].time+1;j<=B[i].time;j++)change(A[j].x,A[j].y);
for(int j=B[i-1].time;j>B[i].time;j--)change(A[j].x,A[j].pre);
ans[B[i].id]=calc();
rev(l);
}
for(int i=1;i<=lb;i++)
printf("%d\n",ans[i]);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: