• LG P4117 [Ynoi2018]五彩斑斓的世界


    Description

    二阶堂真红给了你一个长为 $n$ 的序列 $a$,有 $m$ 次操作

    1. 把区间 $[l,r]$ 中大于 $x$ 的数减去 $x$。
    2. 查询区间 $[l,r]$ 中 $x$ 的出现次数。

    Solution

    CF896E Welcome home, Chtholly数据增强版

    缩小了空间限制,扩大了数据范围,所以必须离线下所有操作,每次只维护一个块,给所有操作更新答案

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    using namespace std;
    int n,m,a[10000005],L[1000005],R[1000005],cnt=1,ll,rr,maxx,ans[1000005];
    int rt[1000005],siz[1000005],tag,fa[1000005],val[1000005];
    const int S=1000;
    struct Node
    {
        int opt,l,r,x;
    }node[1000005];
    inline int read()
    {
        int f=1,w=0;
        char ch=0;
        while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9') w=(w<<1)+(w<<3)+ch-'0',ch=getchar();
        return f*w;
    }
    int find(int x)
    {
        return fa[x]==x?fa[x]:fa[x]=find(fa[x]);
    }
    inline void merge(int p,int x,int y)
    {
        if(rt[y]) fa[rt[x]+(p-1)*S]=rt[y]+(p-1)*S;
        else rt[y]=rt[x],val[rt[y]+(p-1)*S]=y;
        siz[y]+=siz[x],rt[x]=siz[x]=0;
    }
    inline void maintain(int p)
    {
        maxx=tag=0;
        memset(siz,0,sizeof(siz));
        memset(rt,0,sizeof(rt));
        for(int i=ll;i<=rr;i++)
        {
            maxx=max(maxx,a[i]);
            if(!rt[a[i]]) fa[i]=i,rt[a[i]]=i-(p-1)*S,val[i]=a[i];
            else fa[i]=rt[a[i]]+(p-1)*S;
            siz[a[i]]++;
        }
    }
    inline void updateblock(int p,int x)
    {
        if(maxx-tag>=(x<<1))
        {
            for(int i=tag+1;i<=tag+x;i++) if(rt[i]) merge(p,i,i+x);
            tag+=x;
        }
        else
        {
            for(int i=maxx;i>tag+x;i--) if(rt[i]) merge(p,i,i-x);
            maxx=min(maxx,x+tag);
        }
    }
    inline void update(int p,int l,int r,int x)
    {
        for(int i=(p-1)*S+1;i<=min(n,p*S);i++) a[i]=val[find(i)],siz[a[i]]=rt[a[i]]=0,a[i]-=tag;
        for(int i=(p-1)*S+1;i<=min(n,p*S);i++) fa[i]=0;
        tag=0;
        for(int i=l;i<=r;i++) if(a[i]>x) a[i]-=x;
        maxx=tag=0;
        for(int i=ll;i<=rr;i++)
        {
            maxx=max(maxx,a[i]);
            if(!rt[a[i]]) fa[i]=i,rt[a[i]]=i-(p-1)*S,val[i]=a[i];
            else fa[i]=rt[a[i]]+(p-1)*S;
            siz[a[i]]++;
        }
    }
    int main()
    {
        n=read(),m=read();
        for(int i=1;i<=n;i++) a[i]=read();
        for(int i=1;i<=m;i++) node[i]=(Node){read(),read(),read(),read()};
        L[cnt]=1;
        while(L[cnt]+S-1<=n) R[cnt]=L[cnt]+S-1,++cnt,L[cnt]=R[cnt-1]+1;
        R[cnt]=n;
        for(int i=1;i<=cnt;i++)
        {
            ll=L[i],rr=R[i];
            maintain(i);
            for(int j=1;j<=m;j++)
            {
                if(node[j].l>rr||node[j].r<ll) continue;
                if(node[j].opt==1)
                {
                    if(node[j].l<=ll&&node[j].r>=rr) updateblock(i,node[j].x);
                    else update(i,max(ll,node[j].l),min(rr,node[j].r),node[j].x);
                }
                else
                {
                    if(node[j].x+tag>500000) continue;
                    if(node[j].l<=ll&&node[j].r>=rr) ans[j]+=siz[node[j].x+tag];
                    else
                    {
                        int temp=min(rr,node[j].r);
                        for(int k=max(ll,node[j].l);k<=temp;k++) if(val[find(k)]==node[j].x+tag) ans[j]++;
                    }
                }
            }
        }
        for(int i=1;i<=m;i++) if(node[i].opt==2) printf("%d
    ",ans[i]);
        return 0;
    }
    [Ynoi2018]五彩斑斓的世界
  • 相关阅读:
    VCalendar
    xls和xlsx的区别
    alioss的常见问题
    别再写 shǐ 山代码了。。。
    一款高颜值的 MySQL 管理工具,超好用。。
    Spring Boot Admin 横空出世!
    Redis 官方可视化工具,功能真心强大。。。
    Nginx 从安装到高可用,一篇搞定,99% 的人都收藏了。。
    duobule 转 int 问题
    mysql慢sql查询
  • 原文地址:https://www.cnblogs.com/JDFZ-ZZ/p/14044918.html
Copyright © 2020-2023  润新知