• [CF438D]The Child and Sequence


    题目大意:给定一个数列,三个操作:

    1. $1;l;r:$输出区间$[l,r]$的和
    2. $2;l;r;x:$区间$[l,r]$对$x$取模
    3. $3;p;x:$把$p$的值修改成$x$

    题解:线段树,发现对于取模操作,若模数大于被膜数,则不会有影响,可以通过维护最大值跳过,若是对有影响,那么这个数字一定至少会变成原来的一半,所以一个数最多更改$log_2$次,可以承受。

    卡点:我$max$函数写成$min$

    C++ Code:

    #include <cstdio>
    #define maxn 100010
    int s[maxn];
    inline int max(int a, int b) {return a > b ? a : b;}
    namespace Segment_Tree {
    	int n;
    	long long V[maxn << 2];
    	int M[maxn << 2];
    	inline update(int rt) {
    		M[rt] = max(M[rt << 1], M[rt << 1 | 1]);
    		V[rt] = V[rt << 1] + V[rt << 1 | 1];
    	}
    	void build(int rt = 1, int l = 1, int r = n) {
    		if (l == r) {
    			M[rt] = V[rt] = s[l];
    			return ;
    		}
    		int mid = l + r >> 1;
    		build(rt << 1, l, mid);
    		build(rt << 1 | 1, mid + 1, r);
    		update(rt);
    	}
    	int L, R, p, x;
    	void ___add(int rt, int l, int r) {
    		if (l == r) {
    			V[rt] = M[rt] = x;
    			return ;
    		}
    		int mid = l + r >> 1;
    		if (p <= mid) ___add(rt << 1, l, mid);
    		else ___add(rt << 1 | 1, mid + 1, r);
    		update(rt);
    	}
    	inline void add(int pos, int X) {
    		p = pos, x = X;
    		___add(1, 1, n);
    	}
    	void __add(int rt, int l, int r) {
    		if (M[rt] < x) return ;
    		if (l == r) {
    			V[rt] = M[rt] = V[rt] % x;
    			return ;
    		}
    		int mid = l + r >> 1;
    		if (L <= mid) __add(rt << 1, l, mid);
    		if (R > mid) __add(rt << 1 | 1, mid + 1, r);
    		update(rt);
    	}
    	inline void add(int ll, int rr, int X) {
    		L = ll, R = rr, x = X;
    		__add(1, 1, n);
    	}
    	long long __ask(int rt, int l, int r) {
    		if (L <= l && R >= r) return V[rt];
    		int mid = l + r >> 1; long long ans = 0;
    		if (L <= mid) ans = __ask(rt << 1, l, mid);
    		if (R > mid) ans = ans + __ask(rt << 1 | 1, mid + 1, r);
    		return ans;
    	}
    	inline long long ask(int ll, int rr) {
    		L = ll, R = rr;
    		return __ask(1, 1, n);
    	}
    }
    using Segment_Tree::add;
    using Segment_Tree::ask;
    int n, m;
    int main() {
    	scanf("%d%d", &n, &m); Segment_Tree::n = n;
    	for (int i = 1; i <= n; i++) scanf("%d", s + i);
    	Segment_Tree::build();
    	while (m --> 0) {
    		int op, l, r, val;
    		scanf("%d%d%d", &op, &l, &r);
    		if (op == 1) {
    			printf("%lld
    ", ask(l, r));
    		} else if (op == 2) {
    			scanf("%d", &val);
    			add(l, r, val);
    		} else add(l, r);
    	}
    	return 0;
    } 
    

      

  • 相关阅读:
    P3822 [NOI2017]整数
    P4630 [APIO2018] Duathlon 铁人两项
    P3230 [HNOI2013]比赛
    P2570 [ZJOI2010]贪吃的老鼠
    P4576 [CQOI2013]棋盘游戏
    P3256 [JLOI2013]赛车
    P3297 [SDOI2013]逃考
    CF487E Tourists
    设置一个双色球脚本(2)并带颜色输出
    设置一个双色球脚本
  • 原文地址:https://www.cnblogs.com/Memory-of-winter/p/9762562.html
Copyright © 2020-2023  润新知