简单题

题目描述

如题,已知一个数列有n个数,m次操作,你需要进行下面两种操作:
1. 將某个位置的数平均分给一个区间,不能平均分的留下
2. 求出某个位置的值

输入

第一行两个正整数n、m(1<=n,m<=500,000); n表示数字个数,m表示操作的个数
第二行n个整数,a1,a2,a3,...,an代表数列的初始值 (ai<=10^9)
接下来m行,每行2或4个整数,表示一个操作,具体如下:
操作1:1 p,x,y 将第p个数平均分给区间[x,y] (1<=p,x,y<=n)
操作2:2 p        输出第p个数的值
输入数据过大,建议使用scanf输入

输出

对于每个操作2,输出一个整数

样例输入

5 6
1 2 3 4 8
1 5 1 5
2 1 
2 2 
2 3 
2 4
2 5

样例输出

2
3
4
5
4

解题思路:
很明显区间修改,单点查询 

(可以用树状数组和线段树,数据超int)

树状数组:

#include<stdio.h>

#define ll  long long

const int maxn = 5e5+5;

int n,m;

ll a[maxn];

ll t[maxn];

void add(int x,ll v){

    for (;x<=n;x+=x&-x) t[x]+=v;

}

ll query(int x) {

    ll res=0;

    for(;x;x-=x&-x) res+=t[x];

    return res;

}

int main() {

    scanf("%d%d",&n,&m);

    for (int i=1;i<=n;i++) {

        scanf("%lld",&a[i]);

        add(i,a[i]-a[i-1]);

    }

    for (int i=1;i<=m;i++) {

        int op,p,x,y;

        scanf("%d",&op);

        if (op==1) {

            scanf("%d%d%d",&p,&x,&y);

            ll tmp = query(p);

            if (tmp < y-x+1) continue;

            add(p,-tmp/(y-x+1)*(y-x+1));

            add(p+1,tmp/(y-x+1)*(y-x+1));

            add(x,tmp/(y-x+1));

            add(y+1,-tmp/(y-x+1));

        }

        else {

            scanf("%d",&p);

            printf("%lld\n",query(p));

        }

    }

    return 0;

}

线段树

#include<stdio.h>

#define ll      long long

#define lson    rt<<1,l,m

#define rson    rt<<1|1,m+1,r

const int maxn=1<<20;

int n,m;

ll lz[maxn];

inline void push_down(int rt) {

    if (!lz[rt]) return;

    lz[rt<<1]+=lz[rt];

    lz[rt<<1|1]+=lz[rt];

    lz[rt]=0;

}

void build(int rt,int l,int r) {

    if (l==r) {

        scanf("%lld",&lz[rt]);

        return;

    }

    int m=(l+r)>>1;

    build(lson);

    build(rson);

}

void update(int rt,int l,int r,int L,int R,ll v) {

    if (L<=l&&r<=R) {

        lz[rt]+=v;

        return;

    }

    push_down(rt);

    int m=(l+r)>>1;

    if (L<=m) update(lson,L,R,v);

    if (m<R)  update(rson,L,R,v);

}

ll query(int rt,int l,int r,int p) {

    if (l==r) return lz[rt];

    push_down(rt);

    int m=(l+r)>>1;

    if (p<=m) return query(lson,p);

    return query(rson,p);

}

int main() {

    scanf("%d%d",&n,&m);

    build(1,1,n);

    for (int i=1;i<=m;i++) {

        int op,p,x,y;

        scanf("%d",&op);

        if(op==1) {

            scanf("%d%d%d",&p,&x,&y);

            ll tmp=query(1,1,n,p);

            if (tmp<y-x+1) continue;

            update(1,1,n,p,p,-tmp/(y-x+1)*(y-x+1));

            update(1,1,n,x,y,tmp/(y-x+1));

        }

        else {

            scanf("%d",&p);

            printf("%lld\n",query(1,1,n,p));

        }

    }

    return 0;

}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值