zoukankan      html  css  js  c++  java
  • 【BZOJ】4129: Haruna’s Breakfast 树分块+带修改莫队算法

    【题意】给定n个节点的树,每个节点有一个数字ai,m次操作:修改一个节点的数字,或询问一条树链的数字集合的mex值。n,m<=5*10^4,0<=ai<=10^9。

    【算法】树分块+带修改莫队算法

    【题解】和【BZOJ】3052: [wc2013]糖果公园 树分块+待修改莫队算法差不多。

    区别在于如何处理树链信息。考虑对值域分块,由于>n的数字没用,所以对[0,n]分块,维护每一块所含数字个数。

    这样就可以O(1)单点修改,O(√n)查询。(扫描到第一块所含数字不满的块,再块内扫描到第一个没出现的数字)。

    复杂度O(n^(5/3)+n^(3/2))。

    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int maxn=50010;
    int belong[maxn],be[maxn],first[maxn],tot,cnt,top,deep[maxn],f[maxn][22],B,Q;
    int st[maxn],c[maxn],n,m,c0,c1,sz[maxn],num[maxn],mx,pre[maxn],ANS[maxn];
    bool vis[maxn];
    struct edge{int v,from;}e[maxn*2];
    struct mo{int x,y,pre;}a[maxn];
    struct que{int x,y,t,id;}b[maxn];
    bool cmp(que a,que b){return belong[a.x]<belong[b.x]||(belong[a.x]==belong[b.x]&&belong[a.y]<belong[b.y])||
    (belong[a.x]==belong[b.x]&&belong[a.y]==belong[b.y]&&a.t<b.t);}
    void insert(int u,int v){tot++;e[tot].v=v;e[tot].from=first[u];first[u]=tot;}
    void dfs(int x,int fa){
        int p=top;
        for(int j=1;(1<<j)<=deep[x];j++)f[x][j]=f[f[x][j-1]][j-1];
        for(int i=first[x];i;i=e[i].from)if(e[i].v!=fa){
            deep[e[i].v]=deep[x]+1;
            f[e[i].v][0]=x;
            dfs(e[i].v,x);
            if(top-p>=B){
                cnt++;
                while(top>p)belong[st[top--]]=cnt;
            }
        }
        st[++top]=x;//
    }
    int lca(int x,int y){
        if(deep[x]<deep[y])swap(x,y);
        int d=deep[x]-deep[y];
        for(int j=0;(1<<j)<=d;j++)if(d&(1<<j))x=f[x][j];
        if(x==y)return x;
        for(int j=16;j>=0;j--)if((1<<j)<=deep[x]&&f[x][j]!=f[y][j])x=f[x][j],y=f[y][j];
        return f[x][0];
    }
    void rev(int x){
        if(c[x]>n){vis[x]^=1;return;}
        if(!vis[x])sz[be[c[x]]]+=(++num[c[x]]==1);
        else sz[be[c[x]]]-=(--num[c[x]]==0);
        vis[x]^=1;
    }
    void modify(int x,int y){
        if(!vis[x])c[x]=y;
        else rev(x),c[x]=y,rev(x);
    }
    void solve(int x,int y){
        while(x!=y){
            if(deep[x]>deep[y])rev(x),x=f[x][0];
            else rev(y),y=f[y][0];
        }
    }
    int calc(){
        int r;
        for(r=0;r<mx;r++)if(sz[r]<Q)break;
        for(int i=r*Q;i<=n;i++)if(num[i]==0)return i;
        return n;
    }
    int main(){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)scanf("%d",&c[i]),pre[i]=c[i];
        for(int i=1;i<n;i++){
            int u,v;
            scanf("%d%d",&u,&v);
            insert(u,v);insert(v,u);
        }
        B=(int)(pow(n,2.0/3)*0.5)+1;
        Q=(int)(sqrt(n))+1;
        for(int i=0;i<=n;i++)be[i]=i/Q;mx=n/Q;
        dfs(1,0);
        while(top)belong[st[top--]]=cnt;
        for(int i=1;i<=m;i++){
            int s,u,v;
            scanf("%d%d%d",&s,&u,&v);
            if(!s)a[++c0]=(mo){u,v,pre[u]},pre[u]=v;
            else{
                if(belong[u]>belong[v])swap(u,v); 
                b[++c1]=(que){u,v,c0,c1};
            } 
        }
        sort(b+1,b+c1+1,cmp);
        for(int i=1;i<=b[1].t;i++)modify(a[i].x,a[i].y);
        solve(b[1].x,b[1].y);
        int L=lca(b[1].x,b[1].y);
        rev(L);ANS[b[1].id]=calc();rev(L);
        for(int i=2;i<=c1;i++){///
            for(int j=b[i-1].t+1;j<=b[i].t;j++)modify(a[j].x,a[j].y);
            for(int j=b[i-1].t;j>b[i].t;j--)modify(a[j].x,a[j].pre);
            solve(b[i-1].x,b[i].x);solve(b[i-1].y,b[i].y);
            int L=lca(b[i].x,b[i].y);
            rev(L);ANS[b[i].id]=calc();rev(L);
        }
        for(int i=1;i<=c1;i++)printf("%d
    ",ANS[i]);
        return 0;
    }
    View Code

    记得询问先处理1,然后从2开始枚举。

  • 相关阅读:
    新概念4-16
    答疑汇总-02
    理解Marx-8 9 10晚年的思考 马恩关系再认识 一段思想史的公案
    nefu 116
    nefu 115
    【JZOJ3379】查询【主席树】
    【JZOJ1782】Travel【分层图最短路】
    【洛谷P4550】收集邮票【期望概率】
    【洛谷P1001】A+B Problem
    【JZOJ3339】wyl8899和法法塔的游戏【暴力】
  • 原文地址:https://www.cnblogs.com/onioncyc/p/8580599.html
Copyright © 2011-2022 走看看