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

20 篇文章 0 订阅
10 篇文章 0 订阅

题目大意:给定一棵树,每个点有一个非负点权,支持下列操作
1.修改某个点的点权
2.查询某条链上的mex
考虑链上不带修改的版本,我们可以用莫队+分块来搞(链接戳这里)
现在到了树上带修改,果断糖果公园
本来抱着逗比的心态写了一发结果1.4s过了
跟糖果公园的80s完全不成正比啊0.0

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 50500
#define B 1500
using namespace std;

struct abcd{
    int to,next;
}table[M<<1];
int head[M],tot;

int n,m,b1,b2,q,c,L=1,R=1,t;
int fa[M],ancestor[M][16],dpt[M];
int a[M],cnt[M],block[M];
bool v[M];
int belong[M],_cnt;

struct Modifiction{
    int x,from,to,t;
}modifictions[M];

struct Query{
    int x,y,t,ans;
    bool operator < (const Query &q) const
    {
        if( belong[x] != belong[q.x] )
            return belong[x] < belong[q.x];
        if( belong[y] != belong[q.y] )
            return belong[y] < belong[q.y];
        return t < q.t ;
    }
}queries[M];

bool Compare(const Query &q1,const Query &q2)
{
    return q1.t < q2.t ;
}

void Add(int x,int y)
{
    table[++tot].to=y;
    table[tot].next=head[x];
    head[x]=tot;
}

void DFS(int x)
{
    static int stack[M],top;
    int i,bottom=top;
    dpt[x]=dpt[fa[x]]+1;
    for(i=1;i<=15;i++)
        ancestor[x][i]=ancestor[ancestor[x][i-1]][i-1];
    for(i=head[x];i;i=table[i].next)
        if(table[i].to!=fa[x])
        {
            fa[table[i].to]=ancestor[table[i].to][0]=x;
            DFS(table[i].to);
            if(top-bottom>=b1)
            {
                ++_cnt;
                while(top>bottom)
                    belong[stack[top--]]=_cnt;
            }
        }
    stack[++top]=x;
    if(x==1)
    {
        ++_cnt;
        while(top)
            belong[stack[top--]]=_cnt;
    }
}

void Update(int x)
{
    v[x]=true;
    if(a[x]>n) return ;
    cnt[a[x]]++;
    if(cnt[a[x]]==1)
        block[a[x]/b2]++;
}

void Downdate(int x)
{
    v[x]=false;
    if(a[x]>n) return;
    cnt[a[x]]--;
    if(!cnt[a[x]])
        block[a[x]/b2]--;
}

int LCA(int x,int y)
{
    int j;
    if(dpt[x]<dpt[y])
        swap(x,y);
    for(j=15;~j;j--)
        if(dpt[ancestor[x][j]]>=dpt[y])
            x=ancestor[x][j];
    if(x==y) return x;
    for(j=15;~j;j--)
        if(ancestor[x][j]!=ancestor[y][j])
            x=ancestor[x][j],y=ancestor[y][j];
    return ancestor[x][0];
}

void Transfer(int x,int y)
{
    int lca=LCA(x,y);
    for(;x!=lca;x=fa[x])
    {
        if(v[x]) Downdate(x);
        else Update(x);
    }
    for(;y!=lca;y=fa[y])
    {
        if(v[y]) Downdate(y);
        else Update(y);
    }
}

int Get_Mex()
{
    int i,j;
    for(i=0;;i++)
        if(block[i]!=b2)
            for(j=i*b2;;j++)
                if(!cnt[j])
                    return j;
}

int main()
{
    int i,p,x,y;
    cin>>n>>m;
    b1=pow(n,2.0/3.0)+1e-7;
    b2=sqrt(n)+1e-7;
    for(i=1;i<=n;i++)
        scanf("%d",&a[i]);
    for(i=1;i<n;i++)
    {
        scanf("%d%d",&x,&y);
        Add(x,y);Add(y,x);
    }
    DFS(1);
    for(i=1;i<=m;i++)
    {
        scanf("%d%d%d",&p,&x,&y);
        if(p==0)
        {
            modifictions[++c].x=x;
            modifictions[  c].from=a[x];
            modifictions[  c].to=y;
            modifictions[  c].t=i;
            a[x]=y;
        }
        else
        {
            if(belong[x]>belong[y])
                swap(x,y);
            queries[++q].x=x;
            queries[  q].y=y;
            queries[  q].t=i;
        }
    }
    t=c;
    sort(queries+1,queries+q+1);
    for(i=1;i<=q;i++)
    {
        int lca=LCA(queries[i].x,queries[i].y);
        Transfer(L,queries[i].x);
        Transfer(R,queries[i].y);
        L=queries[i].x;
        R=queries[i].y;
        while( modifictions[t].t > queries[i].t )
        {
            if(v[modifictions[t].x])
            {
                Downdate(modifictions[t].x);
                a[modifictions[t].x]=modifictions[t].from;
                Update(modifictions[t].x);
            }
            else
                a[modifictions[t].x]=modifictions[t].from;
            --t;
        }
        while( t<c && modifictions[t+1].t < queries[i].t )
        {
            if(v[modifictions[t+1].x])
            {
                Downdate(modifictions[t+1].x);
                a[modifictions[t+1].x]=modifictions[t+1].to;
                Update(modifictions[t+1].x);
            }
            else
                a[modifictions[t+1].x]=modifictions[t+1].to;
            ++t;
        }
        Update(lca);
        queries[i].ans=Get_Mex();
        Downdate(lca);
    }
    sort(queries+1,queries+q+1,Compare);
    for(i=1;i<=q;i++)
        printf("%d\n",queries[i].ans);
    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值