当前位置: 首页 > 工具软件 > Haruna > 使用案例 >

【BZOJ4129】Haruna’s Breakfast(树上莫队)

仇经武
2023-12-01

【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;
}

转载于:https://www.cnblogs.com/cjyyb/p/8733390.html

 类似资料: