[BZOJ 4129]Haruna’s Breakfast(树上带修改莫队)

Description

Haruna每天都会给提督做早餐! 这天她发现早饭的食材被调皮的 Shimakaze放到了一棵

树上,每个结点都有一样食材,Shimakaze要考验一下她。

每个食材都有一个美味度,Shimakaze会进行两种操作:

1、修改某个结点的食材的美味度。

2、对于某条链,询问这条链的美味度集合中,最小的未出现的自然数是多少。即mex值。

请你帮帮Haruna吧。

Solution

树上带修改莫队

统计答案的时候也分块查询,找到第一个没满的块开始一个一个找

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#define MAXN 50005
using namespace std;
int n,m,a[MAXN],head[MAXN],cnt=0,tot1=0,tot2=0,stack[MAXN],top=0;
int block,block2,tot3=0,belong[MAXN],last[MAXN],deep[MAXN],p[MAXN][22];
int ans=0,res[MAXN],num[MAXN],vis[MAXN],sg[MAXN];
int read()
{
    int x=0,f=1;char c=getchar();
    while(c<‘0‘||c>‘9‘){
        if(c==‘-‘)f=-1;c=getchar();
    }
    while(c>=‘0‘&&c<=‘9‘){
        x=(x<<1)+(x<<3)+c-‘0‘;c=getchar();
    }
    return x*f;
}
struct Node1
{
    int next,to;
}Edges[MAXN*2];
void addedge(int u,int v)
{
    Edges[cnt].next=head[u];
    head[u]=cnt;
    Edges[cnt++].to=v;
}
struct Node2
{
    int u,v,tim,id;
    Node2(int u=0,int v=0,int tim=0,int id=0):u(u),v(v),tim(tim),id(id){}
    bool operator < (const Node2& x) const
    {
        if(belong[u]==belong[x.u])
        {
            if(belong[v]==belong[x.v])
            return tim<x.tim;
            else return belong[v]<belong[x.v];
        }
        else return belong[u]<belong[x.u];
    }
}query[MAXN];
struct Node3
{
    int pos,x,pre;
    Node3(int pos=0,int x=0,int pre=0):pos(pos),x(x),pre(pre){}
}modify[MAXN];
void dfs(int u)
{
    int now=top;
    for(int i=head[u];~i;i=Edges[i].next)
    {
        int v=Edges[i].to;
        if(v==p[u][0])continue;
        p[v][0]=u,deep[v]=deep[u]+1;
        dfs(v);
        if(top-now>=block)
        {
            ++tot3;
            while(top!=now)belong[stack[top--]]=tot3;
        }
    }
    stack[++top]=u;
}
void init()
{
    for(int i=1;(1<<i)<=n;i++)
    {
        for(int j=1;j<=n;j++)
        p[j][i]=p[p[j][i-1]][i-1];
    }
}
int lca(int a,int b)
{
    if(deep[a]>deep[b])swap(a,b);
    int f=deep[b]-deep[a];
    for(int i=0;(1<<i)<=f;i++)
    if(f&(1<<i))b=p[b][i];
    if(a!=b)
    {
        for(int i=(int)log2(n);i>=0;i--)
        if(p[a][i]!=p[b][i])a=p[a][i],b=p[b][i];
        a=p[a][0];
    }
    return a;
}
void Xor(int pos)
{
    if(a[pos]>n)return;
    int b=a[pos]/block2+1;
    if(vis[pos])
    {
        num[a[pos]]--;
        if(!num[a[pos]])sg[b]--;
    }
    else
    {
        if(!num[a[pos]])sg[b]++;
        num[a[pos]]++;
    }
    vis[pos]^=1;
}
void change(int pos,int c)
{
    if(vis[pos])
    Xor(pos),a[pos]=c,Xor(pos);
    else a[pos]=c;
}
void move(int a,int b)
{
    if(deep[a]>deep[b])swap(a,b);
    while(deep[a]!=deep[b])Xor(b),b=p[b][0];
    while(a!=b){Xor(a),Xor(b);a=p[a][0],b=p[b][0];}
}
void work()
{
    int u=1,v=1;
    for(int i=1;i<=tot1;i++)
    {
        for(int j=query[i-1].tim+1;j<=query[i].tim;j++)
        change(modify[j].pos,modify[j].x);
        for(int j=query[i-1].tim;j>query[i].tim;j--)
        change(modify[j].pos,modify[j].pre);
        if(u!=query[i].u)move(u,query[i].u),u=query[i].u;
        if(v!=query[i].v)move(v,query[i].v),v=query[i].v;
        int t=lca(u,v);
        Xor(t);
        int k=1;
        while(sg[k]==block2)k++;
        k=(k-1)*block2;
        while(num[k])k++;
        res[query[i].id]=k;
        Xor(t);
    }
}
int main()
{
    memset(head,-1,sizeof(head));
    n=read(),m=read();
    block=pow(n,2.0/3),block2=sqrt(n);
    for(int i=1;i<=n;i++)last[i]=a[i]=read();
    for(int i=1;i<n;i++)
    {
        int u=read(),v=read();
        addedge(u,v);addedge(v,u);
    }
    dfs(1),init();
    for(int i=1;i<=m;i++)
    {
        int opt=read(),x=read(),y=read();
        if(opt)++tot1,query[tot1]=Node2(x,y,tot2,tot1);
        else modify[++tot2]=Node3(x,y,last[x]),last[x]=y;
    }
    sort(query+1,query+1+tot1);
    work();
    for(int i=1;i<=tot1;i++)printf("%d\n",res[i]);
    return 0;
}
时间: 2024-10-16 03:59:18

[BZOJ 4129]Haruna’s Breakfast(树上带修改莫队)的相关文章

bzoj4129 Haruna’s Breakfast 树上带修莫队+分块

题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=4129 题解 考虑没有修改的序列上的版本应该怎么做: 弱化的题目应该是这样的: 给定一个序列,每次询问区间 \([l, r]\) 中元素的最小没有出现的自然数. 这个弱化的版本可以用离线+线段树二分水掉.但是这个做法显然不太好搬到树上做. 上面的弱化版还有一个莫队做法:可以用莫队维护出来每一个区间的每一个数的出现为次数.把出现过的数通过分块表示出来,于是查询的时候枚举每一个块,寻找第一个不满的

[UOJ #58][WC2013]糖果公园(树上带修改莫队)

Description Solution 树上带修改莫队…!VFK的题解写得很清楚啦 (我的程序为什么跑得这么慢…交的时候总有一种自己在卡测评的感觉…) #include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<algorithm> #define MAXN 100005 typedef long l

【Luogu P4074】[WC2013]糖果公园(树上带修改莫队)

题目描述 Candyland 有一座糖果公园,公园里不仅有美丽的风景.好玩的游乐项目,还有许多免费糖果的发放点,这引来了许多贪吃的小朋友来糖果公园游玩. 糖果公园的结构十分奇特,它由 \(n\) 个游览点构成,每个游览点都有一个糖果发放处,我们可以依次将游览点编号为 \(1\) 至 \(n\).有 \(n-1\) 条双向道路连接着这些游览点,并且整个糖果公园都是连通的,即从任何一个游览点出发都可以通过这些道路到达公园里的所有其它游览点. 糖果公园所发放的糖果种类非常丰富,总共有 \(m\) 种,

BZOJ.2453.维护队列([模板]带修改莫队)

题目链接 带修改莫队: 普通莫队的扩展,依旧从[l,r,t]怎么转移到[l+1,r,t],[l,r+1,t],[l,r,t+1]去考虑 对于当前所在的区间维护一个vis[l~r]=1,在修改值时根据是否在当前区间内修改即可. 块大小取\(O(n^{\frac{2}{3}})\),排序依次按左端点所在块.右端点所在块.修改次数(时间) 复杂度为\(O(n^{\frac{5}{3}})\) (证明在这) #include <cmath> #include <cstdio> #inclu

【BZOJ-3052】糖果公园 树上带修莫队算法

3052: [wc2013]糖果公园 Time Limit: 200 Sec  Memory Limit: 512 MBSubmit: 883  Solved: 419[Submit][Status][Discuss] Description Input Output Sample Input Sample Output 84 131 27 84 HINT Source Solution 树上带修莫队 本质还是树上莫队,详情可以转 BZOJ-3757苹果树 但是这里需要修改,就需要一些特殊的地方

【Luogu】P1903数颜色(带修改莫队)

题目链接 带修改莫队模板. 加一个变量记录现在是第几次修改,看看当前枚举的询问是第几次修改,改少了就改过去,改多了就改回来. 话说我栈用成队列了能过样例?!!!! 从此深信一句话:样例是出题人精心设计的,绞尽脑汁才设计出一个能让错误代码通过的数据qwqqqqq #include<cstdio> #include<cstdlib> #include<cctype> #include<algorithm> #include<cstring> #inc

BZOJ2120数颜色(带修改莫队)

2120: 数颜色 Time Limit: 6 Sec  Memory Limit: 259 MBSubmit: 7384  Solved: 2998[Submit][Status][Discuss] Description 墨 墨购买了一套N支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答墨墨的提问.墨墨会像你发布如下指令: 1. Q L R代表询问你从第L支画笔到第R支画笔中共有几种不同颜色的画笔. 2. R P Col 把第P支画笔替换为颜色Col.为了满足墨墨的要求,你知道你需要

[bzoj2453]维护队列_带修改莫队

维护队列 bzoj-2453 题目大意:给定一个n个数序列,支持查询区间数的种类数,单点修改.不强制在线. 注释:$1\le n,m\le 10^5$. 想法: 带修改莫队裸题. 如果没有修改操作的话,我们就正常按照莫队一样左右移动区间即可. 有了修改操作的话,我们把块变成$n^{\frac{2}{3}}$,关键字变成:左端点所在块.右端点所在块和时间戳. 然后暴力就行了. Code: #include <iostream> #include <cstdio> #include &

F. Machine Learning (带修改莫队)

https://codeforces.com/contest/940/problem/F 题意  给出n个数字,q个询问: 每次询问有两种类型,一种是询问区间,一种是单体修改: 询问区间是询问区间内最小的没用到的大于0的整数: 比如我有一串数字是 1 1 2 2 2 3    那么有两个1 三个2,一个3   出现次数分别有 两 三 一,  那么次数最小的没在区间内出现的是4: 对于这道题,除带修改莫队的模板之外,我们多加两个数组 vis cnt vis数组用来记录某个数出现的频率,cnt用来记