洛谷P4145上帝造题的七分钟——区间修改

题目:https://www.luogu.org/problemnew/show/P4145

区间开平方,可以发现其实开几次就变成1,不需要开了,所以标记一下,每次只去开需要开的地方;

原来写的并查集跳过1或0,然而WA...

(如果a数组<原数组>开int会RE!)

改成线段树,本来想着是这一段区间和只要小于等于其长度就可以跳过了,然而仔细想想完全不是,应为可能有多个0什么的;

所以直接开bool数组标记一下就好了;

不需要pushdown,直接去修改或是跳过。

并查集:

#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
typedef long long ll;
int const MAXN=100005;
int n,m,a[MAXN],fa[MAXN];
ll f[MAXN];
int find(int x)
{
    if(x==fa[x])return x;
    return fa[x]=find(fa[x]);
}
void add(int x,ll y)
{
    for(;x<=n;x+=(x&-x))
        f[x]+=y;
}
void update(int x)
{
    int tmp=a[x];
    a[x]=sqrt(a[x]);
    if(a[x]==1||a[x]==0)fa[x]=find(x+1);
    add(x,a[x]-tmp);
//    for(;x<=n;x+=(x&-x))
//        f[x]-=tmp,f[x]+=a[x];
}
ll query(int x)
{
//    for(int i=1;i<=n;i++)
//        printf("%d ",a[i]);
//    printf("\n");
    ll sum=0;
    for(;x;x-=(x&-x))
        sum+=f[x];
    return sum;
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        fa[i]=i;
        add(i,a[i]);
    }
//    for(int i=1;i<=n;i++)
//        printf("%lld ",f[i]);
//    printf("\n");
    fa[n+1]=n+1;
    scanf("%d",&m);
    while(m--)
    {
        int t,l,r;
        scanf("%d%d%d",&t,&l,&r);
        if(l>r)swap(l,r);
        if(t==0)
        {
            int x=find(l);
            while(x<=r)
            {
                update(x);
                x=find(x+1);
//                cout<<x<<endl;
            }
        }
        if(t==1)
        {
            ll s1=0,s2=0;
            if(l-1)s1=query(l-1);
            s2=query(r);
//            printf("s1=%lld s2=%lld\n",s1,s2);
            printf("%lld\n",s2-s1);
        }
    }
    return 0;
}

代码如下:

#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
typedef long long ll;
int const MAXN=100005;
int n,m;
ll tr[MAXN<<2],a[MAXN];
bool tg[MAXN<<2];
void pushup(int nw)
{
    tr[nw]=tr[nw<<1]+tr[nw<<1|1];
    tg[nw]=(tg[nw<<1]&&tg[nw<<1|1]);
}
//void pushdown(int l,int r,int nw)
//{
//    if(l==r)
//    {
//        tr[nw]=sqrt(tr[nw]);
//        return;
//    }
//    while(lz[nw])
//    {
//        if(tr[nw]<=r-l+1)
//        {
//            lz[nw]=0;
//            break;
//        }
//        int mid=((l+r)>>1);
//        if(tr[nw<<1]>mid-l+1)pushdown(l,mid,nw<<1);
//        if(tr[nw<<1|1]>r-mid)pushdown(mid+1,r,nw<<1|1);
//        pushup(nw);
//        lz[nw]--;
//    }
//}
void update(int l,int r,int L,int R,int nw)
{
    if(tg[nw])return;
    if(l==r)
    {
        tr[nw]=(ll)sqrt(tr[nw]);
        if(tr[nw]==1||tr[nw]==0)tg[nw]=1;
        return;
    }
    int mid=((l+r)>>1);
    if(mid>=L)update(l,mid,L,R,nw<<1);
    if(mid<R)update(mid+1,r,L,R,nw<<1|1);
    pushup(nw);
}
ll query(int l,int r,int L,int R,int nw)
{
//    for(int i=1;i<=n;i++)
//        printf("%d ",a[i]);
//    printf("\n");
    ll sum=0;
    if(l>=L&&r<=R)
    {
//        pushdown(l,r,nw);
        return tr[nw];
    }
    int mid=((l+r)>>1);
    if(mid>=L)sum+=query(l,mid,L,R,nw<<1);
    if(mid<R)sum+=query(mid+1,r,L,R,nw<<1|1);
    return sum;
}
void build(int l,int r,int nw)
{
    if(l==r)
    {
        tr[nw]=a[l];
        if(a[l]==1||a[l]==0)tg[nw]=1;
        return;
    }
    int mid=((l+r)>>1);
    build(l,mid,nw<<1);
    build(mid+1,r,nw<<1|1);
    pushup(nw);
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%lld",&a[i]);
    scanf("%d",&m);
    build(1,n,1);
    while(m--)
    {
        int d,x,y;
        scanf("%d%d%d",&d,&x,&y);
        if(x>y)swap(x,y);
        if(d==0)update(1,n,x,y,1);
        if(d==1)printf("%lld\n",query(1,n,x,y,1));
    }
    return 0;
}

原文地址:https://www.cnblogs.com/Zinn/p/8759211.html

时间: 2024-10-08 15:07:47

洛谷P4145上帝造题的七分钟——区间修改的相关文章

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

思路 每个数不会被开方超过log次,对每个数暴力开方即可 代码 #include <algorithm> #include <cstring> #include <cstdio> #include <cmath> #define int long long using namespace std; struct Node{ int max,sum; }Seg[100100<<2]; int a[100100],n,m; void pushup(i

luogu P4145 上帝造题的七分钟2 / 花神游历各国 维护区间和&amp;&amp;区间开根号

因为开根号能使数字减小得非常快 所以开不了几次(6次?)很大的数就会变成1..... 所以我们可以维护区间最大值,若最大值>1,则继续递归子树,暴力修改叶节点,否则直接return (好像也可以维护区间被开方的次数,但我不会...QAQ) #include<cstdio> #include<iostream> #include<cmath> #define int long long #define R register int #define ls (tr<

BZOJ 3132: 上帝造题的七分钟( 二维BIT )

二维树状数组... 自己YY一下再推一下应该可以搞出来... ---------------------------------------------------------------------------------- #include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #define rep( i , n ) for( int i = 0 ; i <

3038: 上帝造题的七分钟2 [线段树 暴力]

3038: 上帝造题的七分钟2 Time Limit: 3 Sec  Memory Limit: 128 MBSubmit: 1210  Solved: 536[Submit][Status][Discuss] Description XLk觉得<上帝造题的七分钟>不太过瘾,于是有了第二部."第一分钟,X说,要有数列,于是便给定了一个正整数数列.第二分钟,L说,要能修改,于是便有了对一段数中每个数都开平方(下取整)的操作.第三分钟,k说,要能查询,于是便有了求一段数的和的操作.第四分

Bzoj3038 上帝造题的七分钟2 并查集

Time Limit: 3 Sec  Memory Limit: 128 MBSubmit: 1135  Solved: 509 Description XLk觉得<上帝造题的七分钟>不太过瘾,于是有了第二部."第一分钟,X说,要有数列,于是便给定了一个正整数数列.第二分钟,L说,要能修改,于是便有了对一段数中每个数都开平方(下取整)的操作.第三分钟,k说,要能查询,于是便有了求一段数的和的操作.第四分钟,彩虹喵说,要是noip难度,于是便有了数据范围.第五分钟,诗人说,要有韵律,于

tyvj P1716 - 上帝造题的七分钟 二维树状数组区间查询及修改 二维线段树

P1716 - 上帝造题的七分钟 From Riatre    Normal (OI)总时限:50s    内存限制:128MB    代码长度限制:64KB 背景 Background 裸体就意味着身体. 描述 Description “第一分钟,X说,要有矩阵,于是便有了一个里面写满了0的n×m矩阵.第二分钟,L说,要能修改,于是便有了将左上角为(a,b),右下角为(c,d)的一个矩形区域内的全部数字加上一个值的操作.第三分钟,k说,要能查询,于是便有了求给定矩形区域内的全部数字和的操作.第

【BZOJ3132】上帝造题的七分钟 树状数组

[BZOJ3132]上帝造题的七分钟 Description “第一分钟,X说,要有矩阵,于是便有了一个里面写满了0的n×m矩阵. 第二分钟,L说,要能修改,于是便有了将左上角为(a,b),右下角为(c,d)的一个矩形区域内的全部数字加上一个值的操作. 第三分钟,k说,要能查询,于是便有了求给定矩形区域内的全部数字和的操作. 第四分钟,彩虹喵说,要基于二叉树的数据结构,于是便有了数据范围. 第五分钟,和雪说,要有耐心,于是便有了时间限制. 第六分钟,吃钢琴男说,要省点事,于是便有了保证运算过程中

C++之路进阶——线段树(上帝造题的七分钟 2)

2492 上帝造题的七分钟 2 时间限制: 1 s 空间限制: 64000 KB 题目等级 : 大师 Master 题目描述 Description XLk觉得<上帝造题的七分钟>不太过瘾,于是有了第二部. "第一分钟,X说,要有数列,于是便给定了一个正整数数列. 第二分钟,L说,要能修改,于是便有了对一段数中每个数都开平方(下取整)的操作. 第三分钟,k说,要能查询,于是便有了求一段数的和的操作. 第四分钟,彩虹喵说,要是noip难度,于是便有了数据范围. 第五分钟,诗人说,要有韵

3038: 上帝造题的七分钟2

3038: 上帝造题的七分钟2 Time Limit: 3 Sec  Memory Limit: 128 MBSubmit: 662  Solved: 302[Submit][Status] Description XLk觉得<上帝造题的七分钟>不太过瘾,于是有了第二部."第一分钟,X说,要有数列,于是便给定了一个正整数数列.第二分钟,L说,要能修改,于是便有了对一段数中每个数都开平方(下取整)的操作.第三分钟,k说,要能查询,于是便有了求一段数的和的操作.第四分钟,彩虹喵说,要是n