洛谷 P4145 上帝造题的七分钟2 / 花神游历各国

洛谷

这题就是区间开根号,区间求和。我们可以分块做。

我们记布尔数组vis[i]表示第i块中元素是否全部为1。

因为显然当一个块中元素全部为1时,并不需要对它进行根号操作。

我们每个块暴力开根号,因为数字最大\(2^{31}\),所以最多每个数字开几次根号,所以时间复杂度很低。

记录sum[i]表示第i块的总和,所以我们得到这样的算法:

当出现修改操作时,我们暴力修改,如果vis[i]为真,则不对该块进行操作。

而出现查询操作时,直接对正常操作再输出即可。

代码略丑:

#include <bits/stdc++.h>
#define _ putchar('\n')
using namespace std;
typedef int _int;
#define int long long

const int N=100010;
bool vis[N];
int n,m,a[N],len,num;
int pos[N],sum[N],ll[N],rr[N];

inline void read(int &aa)
{
    aa=0;char c=getchar();
    for (;c>'9'||c<'0';c=getchar());
    for (;c>='0'&&c<='9';c=getchar())
        aa=(aa<<3)+(aa<<1)+(c^48);
}

char buffer[N],*S,*T;
inline char Get_Char()
{
    if (S==T) {
        T=(S=buffer)+fread(buffer,1,N,stdin);
        if (S==T) return EOF;
    }
    return *S++;
}

int Get_Int()
{
    char c;
    int re=0;
    for (c=Get_Char();c<'0'||c>'9';c=Get_Char());
    while (c>='0'&&c<='9')
           re=(re<<1)+(re<<3)+(c-'0'),c=Get_Char();
    return re;
}

void print(int x)
{
    if (x>9) print(x/10);putchar(x%10^48);
}

void build()
{
    len=sqrt(n);
    num=n/len;if (n%len) ++num;
    for (int i=1;i<=num;++i)
        ll[i]=(i-1)*len+1,rr[i]=i*len;
    rr[num]=n;
    for (int i=1;i<=num;++i)
        for (int j=ll[i];j<=rr[i];++j)
            sum[i]+=a[j];
    for (int i=1;i<=n;++i)
        pos[i]=(i-1)/len+1;
}

int ask(int l,int r)
{
    int ans=0;
    if (pos[l]==pos[r]) {
        for (int i=l;i<=r;++i)
            ans+=a[i];
        return ans;
    }
    for (int i=l;i<=rr[pos[l]];++i)
        ans+=a[i];
    for (int i=pos[l]+1;i<pos[r];++i)
        ans+=sum[i];
    for (int i=ll[pos[r]];i<=r;++i)
        ans+=a[i];
    return ans;
}

void change(int l,int r)
{
    if (pos[l]==pos[r]) {
        if (vis[pos[l]]) return;
        for (int i=l;i<=r;++i) {
            sum[pos[l]]-=a[i];
            a[i]=sqrt(a[i]);
            sum[pos[l]]+=a[i];
        }
        vis[pos[l]]=1;
        for (int i=ll[pos[l]];i<=rr[pos[l]];++i)
            if (a[i]>1) {vis[pos[l]]=0;break;}
        return;
    }
    if (!vis[pos[l]]) {
        for (int i=l;i<=rr[pos[l]];++i) {
            sum[pos[l]]-=a[i];
            a[i]=sqrt(a[i]);
            sum[pos[l]]+=a[i];
        }
        vis[pos[l]]=1;
        for (int i=ll[pos[l]];i<=rr[pos[l]];++i)
            if (a[i]>1) {vis[pos[l]]=0;break;}
    }
    if (!vis[pos[r]]) {
        for (int i=ll[pos[r]];i<=r;++i) {
            sum[pos[r]]-=a[i];
            a[i]=sqrt(a[i]);
            sum[pos[r]]+=a[i];
        }
        vis[pos[r]]=1;
        for (int i=ll[pos[r]];i<=rr[pos[r]];++i)
            if (a[i]>1) {vis[pos[r]]=0;break;}
    }
    for (int i=pos[l]+1;i<pos[r];++i) {
        if (vis[i]) continue;
        for (int j=ll[i];j<=rr[i];++j) {
            sum[i]-=a[j];
            a[j]=sqrt(a[j]);
            sum[i]+=a[j];
        }
        vis[i]=1;
        for (int j=ll[i];j<=rr[i];++j)
            if (a[j]>1) {vis[i]=0;break;}
    }
}

_int main()
{
    n=Get_Int();
    for (int i=1;i<=n;++i) a[i]=Get_Int();
    build();
    m=Get_Int();
    int opt,l,r;
    while (m--) {
        opt=Get_Int(),l=Get_Int(),r=Get_Int();
        if (l>r) swap(l,r);
        if (opt) print(ask(l,r)),_;
        else change(l,r);
    }
    return 0;
}
posted @ 2018-09-02 21:44  fuyan0101  阅读(342)  评论(0编辑  收藏  举报