zoukankan      html  css  js  c++  java
  • [Noip模拟题]教主的魔法

    题目

    Description

    教主最近学会了一种神奇的魔法,能够使人长高。于是他准备演示给XMYZ信息组每个英雄看。于是N个英雄们又一
    次聚集在了一起,这次他们排成了一列,被编号为1、2、……、N。每个人的身高一开始都是不超过1000的正整数
    。教主的魔法每次可以把闭区间[L, R](1≤L≤R≤N)内的英雄的身高全部加上一个整数W。(虽然L=R时并不符合
    区间的书写规范,但我们可以认为是单独增加第L(R)个英雄的身高)CYZ、光哥和ZJQ等人不信教主的邪,于是他
    们有时候会问WD闭区间 [L, R] 内有多少英雄身高大于等于C,以验证教主的魔法是否真的有效。WD巨懒,于是他
    把这个回答的任务交给了你。

    Input

     第1行为两个整数N、Q。Q为问题数与教主的施法数总和。
     第2行有N个正整数,第i个数代表第i个英雄的身高。
     第3到第Q+2行每行有一个操作:
    (1)若第一个字母为"M",则紧接着有三个数字L、R、W。表示对闭区间 [L, R] 内所有英雄的身高加上W。
    (2)若第一个字母为"A",则紧接着有三个数字L、R、C。询问闭区间 [L, R] 内有多少英雄的身高大于等于C。
    N≤1000000,Q≤3000,1≤W≤1000,1≤C≤1,000,000,000

    Output

    对每个"A"询问输出一行,仅含一个整数,表示闭区间 [L, R] 内身高大于等于C的英雄数。

    Sample Input

    5 3
    1 2 3 4 5
    A 1 5 4
    M 3 5 1
    A 1 5 4

    Sample Output

    2
    3
    【输入输出样例说明】
    原先5个英雄身高为1、2、3、4、5,此时[1, 5]间有2个英雄的身高大于等于4。
    教主施法后变为1、2、4、5、6,此时[1, 5]间有3个英雄的身高大于等于4。


    思路

    这是一道分块题,依然是爆模小边块,但是整个分块要用二分,不然会超时;

    那么二分就需要每一个分块都是排好序的,这样就要开一个数组,存每个分块内排序后的;

    每次改变英雄身高的时候需要,重新建立一次每个分块内排序的数组;

    代码

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    inline ll read()
    {
        ll a=0,f=1; char c=getchar();
        while (c<'0'||c>'9') {if (c=='-') f=-1; c=getchar();}
        while (c>='0'&&c<='9') {a=a*10+c-'0'; c=getchar();}
        return a*f;
    }
    ll n,m,blo;
    ll a[1000001],v[1000001],sv[1000001],b[1000001];
    inline ll L(ll x)//懒人专用函数
    {
        return (x-1)*blo+1;
    }
    inline ll R(ll x)
    {
        return x*blo;
    }
    inline ll dowork(ll x)
    {
        for(ll i=L(a[x]);i<=R(a[x]);i++)
            sv[i]=v[i];//重新构建数组
        sort(sv+L(a[x]),sv+R(a[x])+1);//排序
    }
    inline void findout(ll x,ll y,ll z)
    {
        if(a[x]==a[y])//如果在一个分块,那么暴模
        {
            for(ll i=x;i<=y;i++)
                v[i]+=z;
            dowork(x);//排序
        }
        else
        {
            for(ll i=a[x]+1;i<=a[y]-1;i++)
                b[i]+=z;//大分块要加的,再开一个数组存
            for(ll i=x;i<=R(a[x]);i++)
                v[i]+=z;
            dowork(x);//重构
            for(ll i=L(a[y]);i<=y;i++)
                v[i]+=z;
            dowork(y);//重构
        }
    }
    inline ll reallyans(ll x,ll y,ll z)
    {
        ll sum=0;
        if(a[x]==a[y])
        {
            for(ll i=x;i<=y;i++)
            if(v[i]+b[a[i]]>=z)
                sum++;//暴模,没问题吧
            return sum;
        }
        else
        {
            for(ll i=a[x]+1;i<=a[y]-1;i++)
            {
                ll l=L(i),r=R(i),ss=0,mid;
                while(l<=r)//二分查询
                {
                    mid=(l+r)>>1;
                    if(sv[mid]+b[i]>=z)//如果中间的数字都大于z
                        r=mid-1,           //往左边找是否有满足的
                        ss=R(i)-mid+1;//因为排了序,所以右边的都满足
                    else
                        l=mid+1;
                }
                sum+=ss;
            }
            for(ll i=x;i<=R(a[x]);i++)
            if(v[i]+b[a[i]]>=z)
                sum++;//暴力
            for(ll i=L(a[y]);i<=y;i++)
            if(v[i]+b[a[i]]>=z)
                sum++;//还是暴力
            return sum;
        }
    }
    int main()
    {
        n=read();m=read();blo=sqrt(n);
        for(ll i=1;i<=n;i++)
        {
            v[i]=read();
            a[i]=(i-1)/blo+1;//a数组存每个数在哪个分块
            sv[i]=v[i];//建立一个新数组存每个分块排序的
        }
        ll t=n/blo;
        if(n%blo)
            t++;//统计分块个数
        for(ll i=1;i<=t;i++)
            sort(sv+L(i),sv+R(i)+1);//排序
        char cc[4];
        ll ans;
        for(ll i=1;i<=m;i++)
        {
            scanf("%s",cc);
            ll x=read(),y=read(),z=read();
            if(cc[0]=='M')
                findout(x,y,z);
            else if(cc[0]=='A')
            {
                ans=reallyans(x,y,z);
                printf("%lld
    ",ans);
            }
        }
        return 0;
    }

    有不足的请联系^_^

     
  • 相关阅读:
    c++下使用邮槽实现进程间通信
    c++下基于windows socket的多线程服务器(基于TCP协议)
    C++实现线程同步的几种方式
    c++多线程编程:实现标准库accumulate函数的并行计算版本
    c++多线程在异常环境下的等待
    c++下基于windows socket的服务器客户端程序(基于UDP协议)
    c++下基于windows socket的单线程服务器客户端程序(基于TCP协议)
    C++解决error C4996报错
    Python读取UTF-8编码文件并使用命令行执行时输出结果的问题
    P4655 [CEOI2017]Building Bridges 题解
  • 原文地址:https://www.cnblogs.com/wzx-RS-STHN/p/12902684.html
Copyright © 2011-2022 走看看