• 「线段树」[AHOI2009]维护序列


    双倍经验,还是蓝题,岂不美哉

    题目描述

    老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成。 有长为N的数列,不妨设为(a_1,a_2,…,a_N) 。有如下三种操作形式:
    (1)把数列中的一段数全部乘一个值;
    (2)把数列中的一段数全部加一个值;
    (3)询问数列中的一段数的和,由于答案可能很大,你只需输出这个数模P的值。

    输入格式

    第一行两个整数(N)(P)((1≤P≤1000000000))
    第二行含有(N)个非负整数,从左到右依次为(a_1,a_2,…,a_N), ((0≤a_i≤1000000000,1≤i≤N))
    第三行有一个整数(M),表示操作总数。
    从第四行开始每行描述一个操作,输入的操作有以下三种形式:
    操作1:“1 t g c”(不含双引号)。表示把所有满足(t≤i≤g)(a_i)改为(a_i×c)((1≤t≤g≤N,0≤c≤1000000000))
    操作2:“2 t g c”(不含双引号)。表示把所有满足(t≤i≤g)(a_i)改为(a_i+c) ((1≤t≤g≤N,0≤c≤1000000000))
    操作3:“3 t g”(不含双引号)。询问所有满足(t≤i≤g)(a_i)的和模P的值 ((1≤t≤g≤N))
    同一行相邻两数之间用一个空格隔开,每行开头和末尾没有多余空格。

    输出格式

    对每个操作3,按照它在输入中出现的顺序,依次输出一行一个整数表示询问结果。

    输入输出样例

    输入
    7 43
    1 2 3 4 5 6 7
    5
    1 2 5 5
    3 2 4
    2 3 7 9
    3 1 3
    3 4 7
    
    输出
    2
    35
    8
    

    说明/提示

    【样例说明】

    初始时数列为(1,2,3,4,5,6,7)。

    经过第1次操作后,数列为(1,10,15,20,25,6,7)。

    对第2次操作,和为10+15+20=45,模43的结果是2。

    经过第3次操作后,数列为(1,10,24,29,34,15,16}

    对第4次操作,和为1+10+24=35,模43的结果是35。

    对第5次操作,和为29+34+15+16=94,模43的结果是8。

    测试数据规模如下表所示

    数据编号 1 2 3 4 5 6 7 8 9 10

    N= 10 1000 1000 10000 60000 70000 80000 90000 100000 100000

    M= 10 1000 1000 10000 60000 70000 80000 90000 100000 100000

    Source: Ahoi 2009

    题目题解

    还是三个操作,线段树基本题

    //#define fre yes
    
    #include <cstdio>
    #define int long long
    
    const int N = 100005;
    struct Node {
    	int l, r;
    	long long sum, addv, mul;
    } tree[N << 2];
    int MOD;
    
    long long ans;
    
    void build(int k, int l, int r) {
    	tree[k].l = l; tree[k].r = r; tree[k].addv = 0; tree[k].mul = 1;
    	if(l == r) {
    		scanf("%lld", &tree[k].sum);
    		tree[k].sum %= MOD;
    		return ;
    	}
    	
    	int mid = (l + r) >> 1;
    	build(k * 2, l, mid);
    	build(k * 2 + 1, mid + 1, r);
    	tree[k].sum = (tree[k * 2].sum + tree[k * 2 + 1].sum) % MOD;
    }
    
    void update(int k) {
    	tree[k * 2].addv = (tree[k].mul * tree[k * 2].addv + tree[k].addv) % MOD;
    	tree[k * 2 + 1].addv = (tree[k].mul * tree[k * 2 + 1].addv + tree[k].addv) % MOD;
    	tree[k * 2].mul = (tree[k].mul * tree[k * 2].mul) % MOD;
    	tree[k * 2 + 1].mul = (tree[k].mul * tree[k * 2 + 1].mul) % MOD;
    	tree[k * 2].sum = (tree[k * 2].sum * tree[k].mul + (tree[k * 2].r - tree[k * 2].l + 1) * tree[k].addv) % MOD;
    	tree[k * 2 + 1].sum = (tree[k * 2 + 1].sum * tree[k].mul + (tree[k * 2 + 1].r - tree[k * 2 + 1].l + 1) * tree[k].addv) % MOD;
    	tree[k].addv = 0;
    	tree[k].mul = 1;
    }
    
    void mul_interval(int k, int l, int r, int x) {
    	if(tree[k].l >= l && tree[k].r <= r) {
    		tree[k].sum = (tree[k].sum * x) % MOD;
    		tree[k].addv = (tree[k].addv * x) % MOD;
    		tree[k].mul = (tree[k].mul * x) % MOD;
    		return ;
    	}
    	
    	if(tree[k].addv || tree[k].mul != 1) update(k);
    	int mid = (tree[k].l + tree[k].r) >> 1;
    	if(mid >= l) mul_interval(k * 2, l, r, x);
    	if(mid < r) mul_interval(k * 2 + 1, l, r, x);
    	tree[k].sum = (tree[k * 2].sum + tree[k * 2 + 1].sum) % MOD;
    }
    
    void add_interval(int k, int l, int r, int x) {
    	if(tree[k].l >= l && tree[k].r <= r) {
    		tree[k].sum = (tree[k].sum + (tree[k].r - tree[k].l + 1) * x) % MOD;
    		tree[k].addv = (tree[k].addv + x) % MOD;
    		return ;
    	}
    	
    	if(tree[k].addv || tree[k].mul != 1) update(k);
    	int mid = (tree[k].l + tree[k].r) >> 1;
    	if(mid >= l) add_interval(k * 2, l, r, x);
    	if(mid < r) add_interval(k * 2 + 1, l, r, x);
    	tree[k].sum = (tree[k * 2].sum + tree[k * 2 + 1].sum) % MOD;
    }
    
    void query(int k, int l, int r) {
    	if(tree[k].l >= l && tree[k].r <= r) {
    		ans = (ans + tree[k].sum) % MOD;
    		return ;
    	}
    	
    	if(tree[k].addv || tree[k].mul != 1) update(k);
    	int mid = (tree[k].l + tree[k].r) >> 1;
    	if(mid >= l) query(k * 2, l, r);
    	if(mid < r) query(k * 2 + 1, l, r);
    }
    
    signed main() {
    	static int n, m;
    	scanf("%lld %lld", &n, &MOD);
    	build(1, 1, n);
    	scanf("%lld", &m);
    	for (int i = 1; i <= m; i++) {
    		int k;
    		scanf("%lld", &k);
    		if(k == 1) {
    			int l, r, x;
    			scanf("%lld %lld %lld", &l, &r, &x);
    			mul_interval(1, l, r, x);
    		}
    		if(k == 2) {
    			int l, r, x;
    			scanf("%lld %lld %lld", &l, &r, &x);
    			add_interval(1, l, r, x);
    		}
    		if(k == 3) {
    			int l, r; ans = 0;
    			scanf("%lld %lld", &l, &r);
    			query(1, l, r);
    			printf("%lld
    ", ans % MOD);
    		}
    	} return 0;
    }
    
  • 相关阅读:
    运行ConnectionDemo时遇到的问题及解决方案
    xampp启动MySQL出现Error: MySQL shutdown unexpectedly.
    20175227张雪莹 2018-2019-2 《Java程序设计》第八周学习总结
    KMS
    MAC 添加共享,脚本执行
    zabbix企业应用之windows系统安装omsa硬件监控
    SCCM大致安装过程,参考前辈教程完成部署
    MAC加域重复跳出---"talagent"想使用“本地项目” 的钥匙串
    CentOS Linux解决 Device eth0 does not seem to be present
    zabbix3.0.4 部署History
  • 原文地址:https://www.cnblogs.com/Nicoppa/p/11445895.html
Copyright © 2020-2023  润新知