BZOJ 3343: 教主的魔法|分块

分块暴力对每一个块排序,询问如果跨过了整个块,那么就查询整个块,对排好序的块二分答案,两边在块外的就暴力排序,二分答案
区间修改如果跨过了整个块,就在块上标记,否则暴力修改,重新给块排序

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<queue>
#include<vector>
#include<set>
#include<map>
#include<iostream>
#include<algorithm>
using namespace std;
int sc()
{
    int i=0;char c=getchar();
    while(c>'9'||c<'0')c=getchar();
    while(c>='0'&&c<='9')i=i*10+c-'0',c=getchar();
    return i;
}
int a[1000005],block_st[1005][1005],block_tag[1005],block_sum[1005];
int bl[1000005],st[2222];
int block,m,n;
bool cmp(int a,int b){return a>b;}
int find(int *w,int r,int K)
{
    int l=1,ans=0;
    while(l<=r)
    {
        int mid=l+r>>1;
        if(w[mid]>=K)ans=mid,l=mid+1;
        else r=mid-1;
    }
    return ans;
}
int main()
{
    n=sc(),m=sc();block=sqrt(n);
    for(int i=1;i<=n;i++)a[i]=sc();
    for(int i=1;i<=n;i++)
    {
        bl[i]=(i-1)/block+1;
        block_sum[(i-1)/block+1]++;
        block_st[(i-1)/block+1][block_sum[(i-1)/block+1]]=a[i];
    }
    for(int i=1;i*block+1<=n;i++)
        sort(block_st[i]+1,block_st[i]+block_sum[i]+1,cmp);
    for(int i=1;i<=m;i++)
    {
        char s[5]; scanf("%s",s);
        if(s[0]=='A')
        {
            int l=sc(),r=sc(),k=sc();
            if(bl[l]==bl[r])
            {
                int top=0;
                for(int j=l;j<=r;j++)st[++top]=a[j];
                sort(st+1,st+top+1,cmp);
                printf("%d\n",find(st,top,k));
            }
            else
            {
                int x=bl[l],y=bl[r];
                int ans=0,top=0;
                for(int j=x+1;j<y;j++)
                    ans+=find(block_st[j],block_sum[j],k-block_tag[j]);
                for(int j=l;bl[j]==bl[l];j++) st[++top]=a[j]+block_tag[x];
                for(int j=r;bl[j]==bl[r];j--) st[++top]=a[j]+block_tag[y];
                sort(st+1,st+top+1,cmp);
                printf("%d\n",ans+find(st,top,k));
            }   
        }
        else
        {
            int l=sc(),r=sc(),k=sc();
            if(bl[l]==bl[r])
            {
                for(int j=l;j<=r;j++)a[j]+=k;
                int top=0,x=bl[l];
                for(int j=(x-1)*block+1;bl[j]==x;j++)block_st[x][++top]=a[j];
                sort(block_st[x]+1,block_st[x]+top+1,cmp);
            }
            else
            {
                int x=bl[l],y=bl[r],top;
                for(int j=x+1;j<y;j++)block_tag[j]+=k;
                for(int j=l;bl[j]==x;j++)a[j]+=k;
                for(int j=r;bl[j]==y;j--)a[j]+=k;
                top=0;
                for(int j=(x-1)*block+1;bl[j]==x;j++)block_st[x][++top]=a[j];
                sort(block_st[x]+1,block_st[x]+top+1,cmp);
                top=0;
                for(int j=(y-1)*block+1;bl[j]==y;j++)block_st[y][++top]=a[j];
                sort(block_st[y]+1,block_st[y]+top+1,cmp);
            }
        }
    }
    return 0;
}

你可能感兴趣的:(分块)