CDOJ 1292 卿学姐种花 暴力 分块 线段树

转自:卿学姐种花
题目连接:

http://acm.uestc.edu.cn/#/problem/show/1292
Description

众所周知,在喵哈哈村,有一个温柔善良的卿学姐。

卿学姐喜欢和她一样美丽的花。所以卿学姐家的后院有很多的花坛。

卿学姐有n
个花坛,一开始第i个花坛里有A[i]

朵花。每过一段时间,卿学姐都会在花坛里种上新的花。

作为一个聪明的学姐,卿学姐的种花方式也是与众不同 , 每一次,卿学姐会在第x
个花坛种上y朵花,然后在第x+1个花坛上种上y−1朵花,再在第x+2个花坛上种上y−2

朵花……以此类推,直到种到最后一个花坛,或者不需要种花为止。

喵哈哈的村民们都喜欢去卿学姐的后院赏花,沈宝宝也不例外。然而沈宝宝可不是省油的灯,怎么可能会老老实实地赏花呢。每次沈宝宝来时,都会随机询问卿学姐在第i

个花坛有多少朵花。

花坛的花实在太多了,卿学姐实在是数不过来。于是现在她向你求助,希望你能帮她数出花坛里多少朵花。
Input

第一行输入两个整数,花坛个数N
和操作次数Q

第二行N
个整数A[1],A[2],A[3]…..A[N]。 ( 1≤A[i]≤231

)

接下来Q

行,每行一个操作。

1 x y 表示卿学姐会在x

号花坛种y

朵花,并按相应的规律在后面的花坛上种花。

2 x 表示沈宝宝问卿学姐第x

个花坛有多少朵花。

数据保证:

1≤N≤104

1≤Q≤2∗106

x108x 代表操作 2

的询问下标

对于操作 1
, 1≤x≤N,1≤y≤109

对于操作 2
, 1≤x≤N

Output

对于每个询问操作,按顺序输出答案对772002+233

取模的值。
Sample Input

6 3
1 2 3 2 1 2
1 2 3
2 3
2 6
Sample Output

5
2
Hint
题意
题解:

最简单的方法,O(N)去更新,然后O(1)去查询就好了,但是显然这样子会TLE的

然后我们注意,我们发现这道保证查询操作的sigmax<=1e8

所以我们把这个变成O(1)更新,O(N)查询就好了,这个东西打个延时标记就好了。

比如1 x y

我只需要使得lazy[x]+=y,表示x这个位置需要往下更新的大小增加y

ed[x+y]++,表示某一个更新会在x+y这个位置停止。

num[x]++,表示x这个位置多了一个更新。

然后我们查询2 x的时候

我们只需要从1这个位置,一直for到x这个位置就好了,然后处理我们刚才打上去的延迟标记。

add表示现在累计了多少的值,Num表示现在我有多少个更新。

add+=lazy[i],

Num+=num[i],Num-=ed[i]。

a[i] = (a[i]+add)%mod;

add-=Num。显然走一步,就会减少Num

然后就完了~

然后有人会深入去思考,假设没有那个 sigma x<=1e8怎么办?

其实查询和更新均摊一下就好了:

有两种,

1.分块,这个方法可以把查询和更新操作都均摊到O(sqrt(n)),直接暴力更新这个值在这个块内的数据,然后再暴力更新其他大块就好了

2.线段树,直接暴力去怼线段树就好了

int n,Q;
LL a[N];
LL num[N],ed[N],lazy[N];


void update(int x,int y){
    lazy[x]+=y;
    num[x]++;
    ed[min(n+1,x+y)]++;
}
LL query(int x){
    LL Num=0;
    LL add=0;
    for(int i=1;i<=x;++i){
        add+=lazy[i];
        Num+=num[i];
        Num-=ed[i];
        num[i]=ed[i]=lazy[i]=0;
        a[i]=(a[i]+add)%mod;
        add-=Num;
    }
    lazy[x+1]+=add;num[x+1]+=Num;
    return a[x];
}
int main(){
    //freopen("in.txt","r",stdin);
    while(~scanf("%d%d",&n,&Q)){
        for(int i=1;i<=n;++i)scanf("%lld",&a[i]),a[i]%=mod;
        while(Q--){
            int op;scanf("%d",&op);
            if(op==1){
                int x,y;scanf("%d%d",&x,&y);
                update(x,y);
            }else{
                int x;
                scanf("%d",&x);
                printf("%lld\n",query(x));
            }
        }
    }
}

迷之分块

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+7;
const int mod = 772002+233;
long long a[maxn];
int l[1000],r[1000];
int block,num,belong[maxn];
long long lazy[maxn],number[maxn],ed[maxn];
int n,m;
void updata(int x,long long y)
{
    for(int i=x;i<=r[belong[x]];i++)
    {
        a[i]=(a[i]+y)%mod;
        y--;if(y==0)return;
    }
    for(int i=belong[x]+1;i<=num;i++)
    {
        lazy[l[i]]+=y;
        number[l[i]]++;
        if(y<(r[i]-l[i]+1))
        {
            ed[l[i]+y]++;
            break;
        }
        y-=(r[i]-l[i]+1);
    }
}
long long query(int x)
{
    long long add = 0;
    long long Num = 0;
    for(int i=l[belong[x]];i<=r[belong[x]];i++)
    {
        add+=lazy[i];
        Num+=number[i];
        Num-=ed[i];
        lazy[i]=number[i]=ed[i]=0;
        a[i]=(a[i]+add)%mod;
        add-=Num;
    }
    return a[x]%mod;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)scanf("%lld",&a[i]),a[i]%=mod;;
    block=(int)sqrt(n+0.5);
    num = n/block;
    if(n%block)num++;
    for(int i=1;i<=num;i++)
        l[i]=(i-1)*block+1,r[i]=i*block;
    r[num]=n;

    for(int i=1;i<=n;i++)
        belong[i]=(i-1)/block+1;

    for(int i=1;i<=m;i++)
    {
        int op,x,y;
        scanf("%d",&op);
        if(op==1)
        {
            scanf("%d%lld",&x,&y);
            updata(x,y);
        }
        else
        {
            scanf("%d",&x);
            printf("%lld\n",query(x));
        }
    }
}

线段树:

#include <iostream>
#include <algorithm>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#define lid (id << 1)
#define rid (id << 1 | 1)
using namespace std;
typedef long long LL;
const int N = 1e4 + 10;
const LL MOD = 772002 + 233;

int n,q;
LL a[N];
struct Segtree{
    int l,r;
    LL time,cnt;
}tr[N * 4];

void Segtree_Initial(int id,int l,int r)
{
    tr[id].l = l;
    tr[id].r = r;
    tr[id].time = tr[id].cnt = 0;
    if(l != r)
    {
        int mid = (l + r) >> 1;
        Segtree_Initial(lid,l,mid);
        Segtree_Initial(rid,mid + 1,r);
    }
}

void Segtree_Update(int id,int l,int r,LL x)
{
    if(l > r) return;
    if(tr[id].l == l && tr[id].r == r)
    {
        tr[id].time++;
        tr[id].cnt += x;
        return;
    }

    int mid = (tr[id].l + tr[id].r) >> 1 ;
    Segtree_Update(lid,l,min(mid , r),x);
    Segtree_Update(rid,max(l , mid + 1),r,x - max(mid + 1 - l , 0) );
}

LL Segtree_Query(int id,int pos)
{
    if(tr[id].l > pos || tr[id].r < pos) return 0;

    LL tot = tr[id].cnt - (1LL * (pos - tr[id].l) * 1LL) * tr[id].time;

    if(tr[id].l != tr[id].r) tot += Segtree_Query(lid,pos) + Segtree_Query(rid,pos);
    return tot;
}

void init()
{
    scanf("%d%d",&n,&q);
    for(int i = 1;i <= n;i++)
      scanf("%lld",&a[i]);
    Segtree_Initial(1,1,n);
}

void work()
{
    int s,pos,x,l,r;
    LL y,ans;
    for(int i = 1;i <= q;i++)
    {
        scanf("%d",&s);
        if(s == 1)
        {
            scanf("%d%lld",&x,&y);
            l = x,r = x + int(y) - 1;
            if(r >= n) r = n;
            Segtree_Update(1,l,r,y);
        }
        else
        {
            scanf("%d",&pos);
            ans = (Segtree_Query(1,pos) + a[pos]) % MOD;
            printf("%lld\n",ans);
        }
    }
}

int main()
{
    init();
    work();
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值