zoukankan      html  css  js  c++  java
  • [2019长沙长郡中学集训]加法

    题面描述

    给定一个(n)阶排列(b),要求维护一个初值全为(0)的数组({a_i}),支持(q)次如下操作:

    • 给出(l,r),将(a_l,a_{l+1},......,a_{r-1},a_r),全部+1
    • 给出(l,r),查询(sum_{i=l}^{r} lfloor frac{{b[i]}}{a[i]} floor)

    输入格式

    第一行输入两个整数(n,q)
    第二行(n)个正整数表示排列(b)
    接下来(q)行,每行三个正整数(op,l,r,op=1)表示第一种操作,(op=2)表示第二种操作

    输出格式

    对于每次询问,输出一行一个非负整数表示答案。

    数据规模

    对于$%30 $的数据,(1leq n,q leq 3000.)
    对于另外(\%30)的数据,当(op=2)时,有(l=1,r=n)
    对于(\%100)的数据,(1leq n,q leq 3 imes 10^5,opin{1,2},1leq l leq r leq n.)

    样例输入

    5 10
    1 5 2 4 3
    1 1 4
    2 1 4
    1 2 5
    1 3 5
    2 1 5
    1 2 4
    2 1 4
    1 2 5
    1 2 2
    2 1 5

    样例输出

    1
    2
    4
    6

    题解

    考试的时候爆掉了。。。卡常是真的恶心QAQ
    先考虑部分分的做法
    对于3000以内的数据,我们直接暴力循环。比较闲的同学可以考虑写两个线段树,一个用来更新a数组的值,另一个用来维护a[i]/b[i]。
    对于查询操作恒查询整个区间的数据,我们可以只维护一个线段树,用于维护a数组,并区间查询整个区间的ans即可。
    ---------------------------以下是正解部分-----------------------------
    观察原式可以发现,我们最后的取值要向下取整,则每一个位置(i)产生更多贡献的唯一办法就是使a[i]成为b[i]的k倍(k>0)。因此,我们用一个线段树记录b[i]的值,用数组记录b的原值,同时用另一棵线段树维护答案,每次op=1时使区间内的每一个b[i]全部-1。当b[i]=0时我们使当前位的贡献+1,并重置b[i]的值为初始值。每次单独变换的复杂度为(O(log n)),每次查询时递归进第二棵线段树中查找,因此总的复杂度是(O(q log^2n))
    为什么要用减法而不是加法呢?
    如果用加法运算我们需要同时维护maxa和minb的值,而如果用减法只用维护一个min就好了

    #include<bits/stdc++.h>
    #define il inline
    #define re register
    typedef long long ll;
    using namespace std;
    const int maxn = 3e5 + 10;
    int n, q, ans;
    int b[maxn];
    int trmin[maxn<<2], tradd[maxn<<2], lazy[maxn<<2];
    //
    il void init() {
    	memset(lazy, 0, sizeof(lazy));
    	memset(trmin, 0, sizeof(trmin));
    	memset(tradd, 0, sizeof(tradd));
    }
    //
    il void pushup(int id) {
    	trmin[id] = min(trmin[id<<1], trmin[id<<1|1]);
    	tradd[id] = tradd[id<<1] + tradd[id<<1|1];
    	return ;
    }
    //
    il void build(int id, int l, int r) {
    	if(l == r) {
    		trmin[id] = b[l];
    		return;
    	}
    	int mid = (l+r)>>1;
    	build(id<<1, l, mid);
    	build(id<<1|1, mid+1, r);
    	pushup(id);
    }
    il void pushdown(int id) {
    	if (lazy[id]) {
            lazy[id << 1] += lazy[id];
            lazy[id << 1 | 1] += lazy[id];
            trmin[id << 1] -= lazy[id];
            trmin[id << 1 | 1] -= lazy[id];
            lazy[id] = 0;
        }
    }
    il void update(int id, int l, int r, int x, int y) {
    	if(trmin[id] > 1 && x <= l && r <= y) {
    		lazy[id]++;
    		trmin[id]--;
    		return ;
    	}
    	if(trmin[id] == 1 && l == r) {
    		tradd[id]++;
    		trmin[id] = b[l];
    		lazy[id] = 0;
    		return ;
    	}
    	pushdown(id);
    	int mid = (l + r) >> 1;
        if (x <= mid)
            update(id << 1, l, mid, x, y);
        if (y > mid)
            update(id << 1 | 1, mid + 1, r, x, y);
        pushup(id);
    }
    il int query(int id, int l, int r, int x, int y) {
    	if(x <= l && r <= y) return tradd[id];
    	if(trmin[id] == 0) update(1, 1, n, x, y);
    	pushdown(id);
    	int sum = 0;
    	int mid = (l+r) >> 1;
    	if(x <= mid) sum += query(id<<1, l, mid, x, y);
    	if(y > mid) sum += query(id<<1|1, mid+1, r, x, y);
    	pushup(id);
    	return sum;
    }
    signed main(){
    	init();
    	scanf("%d%d", &n, &q);
    	for(re int i = 1; i <= n; ++i) scanf("%d", &b[i]);
    	build(1, 1, n);
    	int op, l, r;
    	while(q--) {
    		scanf("%d%d%d", &op, &l, &r);
    		if(op == 1)
    			update(1, 1, n, l, r);
    		else
    			printf("%d
    ", query(1, 1, n, l, r));
    	}
    	return 0;
    } 
    
    
  • 相关阅读:
    兼容Android 和 ios JavaScript copy paste
    hello-循环神经网络(RNN)原理
    236. Lowest Common Ancestor of a Binary Tree
    Tensorflow 之模型内容可视化
    CUDA,cudnn一些常见版本问题
    MongoDB国内学术研究(部分)
    Unsupported major.minor version 52.0
    WebService的两种方式SOAP和REST比较
    廖雪峰老师的git在线教程
    MAVEN ERROR : Dynamic Web Module 3.0 requires Java 1.6 or newer
  • 原文地址:https://www.cnblogs.com/Chen574118090/p/11563154.html
Copyright © 2011-2022 走看看