• 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 leq A[i] leq 2^{31} $ )

    接下来(Q)行,每行一个操作。

    1. 1 x y 表示卿学姐会在(x)号花坛种(y)朵花,并按相应的规律在后面的花坛上种花。

    2. 2 x 表示沈宝宝问卿学姐第(x)个花坛有多少朵花。

    数据保证:

    • $1 leq N leq 10^4 $

    • $1 leq Q leq {2*10^6} $

    • $sum x leq 10^8 (,)x$代表操作 (2) 的询问下标

    • 对于操作 $ 1 $ , (1 leq x leq N)(1 leq y leq 10^9)

    • 对于操作 $ 2 $ , (1 leq x leq 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.线段树,直接暴力去怼线段树就好了

    下面是代码:

    正解大暴力

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn = 1e4+5;
    const int mod = 772002+233;
    
    long long a[maxn],lazy[maxn],num[maxn],ed[maxn];
    int n,m;
    void updata(int x,long long y)
    {
        lazy[x]+=y;
        num[x]++;
        ed[min(1ll*n+1,x+y)]++;
    }
    long long query(int x)
    {
        long long add = 0;
        long long Num = 0;
        for(int i=1;i<=x;i++)
        {
            add+=lazy[i];
            Num+=num[i];
            Num-=ed[i];
            lazy[i]=num[i]=ed[i]=0;
            a[i]=(a[i]+add)%mod;
            add-=Num;
        }
        lazy[x+1]+=add,num[x+1]+=Num;
        return a[x];
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)scanf("%lld",&a[i]),a[i]%=mod;
        for(int i=1;i<=m;i++)
        {
            int op,x;
            long long y;
            scanf("%d",&op);
            if(op==1)
            {
                scanf("%d%lld",&x,&y);
                updata(x,y);
            }
            else
            {
                scanf("%d",&x);
                printf("%lld
    ",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
    ",query(x));
            }
        }
    }
    

    线段树(1)

    #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
    ",ans);
            }
        }
    }
    
    int main()
    {
        init();
        work();
    }
    

    线段树(2)

    #include <cstdio>
    
    #define MAX_N 10004
    #define lchild l, m, v << 1
    #define rchild m + 1, r, v << 1 | 1
    
    typedef long long ll;
    
    int N, Q;
    ll A[MAX_N];
    
    const ll mod = 772002 + 233;
    
    void add(ll &x, ll a){
        x = (x + a) % mod;
    }
    
    struct SegmentTree{
    	struct node{
    		ll coverTime;
    		ll headNum;
    	}tree[MAX_N * 4];
    
    	SegmentTree();
    	void build(int, int, int);
    	void pushDown(int, int, int);
    	void update(int, int, ll, int, int, int);
    	ll query(int, int, int, int);
    }seg;
    
    SegmentTree::SegmentTree(){
    	for(int i = 0; i < MAX_N * 4; i++)
    		tree[i].coverTime = tree[i].headNum = 0;
    }
    
    void SegmentTree::build(int l = 1,int r = N, int v = 1){
    	if(l == r){
    		tree[v].headNum = A[l];
    		return;
    	}
    	int m = (l + r) >> 1;
    	build(lchild);
    	build(rchild);
    }
    
    void SegmentTree::pushDown(int l, int r, int v){
    	int m = (l + r) >> 1;
    	add(tree[v << 1].coverTime, tree[v].coverTime);
    	add(tree[v << 1 | 1].coverTime, tree[v].coverTime);
    	add(tree[v << 1].headNum, tree[v].headNum);
    	add(tree[v << 1 | 1].headNum, (tree[v].headNum - (m - l + 1) * tree[v].coverTime % mod) % mod);
    	tree[v].coverTime = tree[v].headNum = 0; 
    }
    
    void SegmentTree::update(int L, int R, ll x, int l = 1, int r = N, int v = 1){
    	if(L <= l && r <= R){
    		add(tree[v].headNum, x - (l - L));
    		add(tree[v].coverTime, 1);
    		return;
    	}
    	if(tree[v].coverTime) pushDown(l, r, v);
    	int m = (l + r) >> 1;
    	if(L <= m) SegmentTree::update(L, R, x, lchild);
    	if(R > m) SegmentTree::update(L, R, x, rchild);
    } 
    
    ll SegmentTree::query(int a, int l = 1, int r = N, int v = 1){
    	if(l == r) 
    		return (tree[v].headNum %mod + mod) % mod;
    	if(tree[v].coverTime) pushDown(l, r, v);
    	int m = (l + r) >> 1;
    	if(a <= m) return SegmentTree::query(a, lchild);
    	else return SegmentTree::query(a, rchild);
    }
    
    int main(){
    	scanf("%d%d", &N, &Q);
    	for(int i = 1; i <= N; i++)
    		scanf("%lld", &A[i]);
    	seg.build();
    	while(Q--){
    		int op, x, y;
    		scanf("%d%d", &op, &x);
    		if(op == 1){
    			scanf("%d", &y);
    			int z = x + y - 1 > N ? N : x + y - 1;
    			seg.update(x, z, y);
    		}
    		else
    			printf("%lld
    ", seg.query(x));
    	}
    	return 0;
    }
  • 相关阅读:
    微信小程序之界面交互反馈
    微信小程序引入腾讯地图API方法
    微信小程序动态修改页面标题setNavigationBarTitle
    JavaScript中||和&&的运算
    微信小程序 使用include导入wxml文件注意的问题
    idea中文乱码及maven项目配置问题
    Linux常用命令大全
    2018年深圳,武汉房价走势分析
    redis安装,windows,linux版本并部署服务
    dubbo基础学习总结
  • 原文地址:https://www.cnblogs.com/qscqesze/p/5316906.html
Copyright © 2020-2023  润新知