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\n",ans[i]);
    return 0;
}
[Ynoi2018]五彩斑斓的世界

 

posted @ 2020-11-26 22:12  QDK_Storm  阅读(126)  评论(0编辑  收藏  举报