zoukankan      html  css  js  c++  java
  • 洛谷 P2023 [AHOI2009]维护序列 题解

    P2023 [AHOI2009]维护序列

    题目描述

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

    输入格式

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

    输出格式

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

    输入输出样例

    输入 #1

    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

    输出 #1

    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

    【思路】

    线段树
    线段树2改一下输入顺序就可以A掉,,,,,
    模板的话去看线段树2就好了
    我只在这里说几个易错或者难懂的地方

    【取模】

    在每一次有加法或者有乘法
    涉及到运算的地方能模的都模一下就好了

    【乘法和加法】

    原来线段树1模板里面有一个lazy
    那是因为有加法这种运算
    现在有加法和乘法这两种运算
    那就开两个类似lazy的东西储存就好了

    【lazy标记的修改】

    在修改加法lazy标记的时候就正常修改就好了
    但是修改乘法的时候就不行了
    因为前面可能有加过的数
    所以还要连带着一起修改一下加法的lazy标记
    因为入过前面加过某个数
    那现在就是
    (a + b)
    这个时候如果乘上一个数c
    (a +b) * c = ac + bc
    a乘了c,加法的lazy标记也乘了c所以要修改加法的标记

    【完整代码】

    #include<iostream>
    #include<cstdio>
    #define int long long
    #define lson (k << 1)
    #define rson (k << 1 | 1)
    using namespace std;
    const int Max = 100005;
    int read()
    {
    	int sum = 0,fg = 1;
    	char c = getchar();
    	while(c < '0' || c > '9')
    	{
    		if(c == '-')fg = -1;
    		c = getchar();
    	}
    	while(c >= '0' && c <= '9')
    	{
    		sum = sum * 10 + c - '0';
    		c = getchar(); 
    	}
    	return sum * fg;
    }
    struct node
    {
    	int l,r;
    	int sum;
    	int cheng,jia;
    }a[Max << 2];
    int n,m,p;
    int ans;
    int opl,opr,opx;
    void build(int k,int l,int r)
    {
    	a[k].l = l,a[k].r = r;
    	a[k].cheng = 1;
    	if(l == r)
    	{
    		a[k].sum = read();
    		a[k].sum %= p;
    		return;
    	}
    	int mid = (l + r) >> 1;
    	build(lson,l,mid);
    	build(rson,mid + 1,r);
    	a[k].sum = a[lson].sum + a[rson].sum;
    	a[k].sum %= p;
    	return;
    }
    
    void down(int k)
    {
    	if(a[k].cheng != 1 || a[k].jia != 0)
    	{
    		a[lson].sum = (a[lson].sum * a[k].cheng % p + a[k].jia * (a[lson].r - a[lson].l + 1) % p);
    		a[lson].sum %= p;
    		a[rson].sum = (a[rson].sum * a[k].cheng % p + a[k].jia * (a[rson].r - a[rson].l + 1) % p);
    		a[rson].sum %= p;
    		a[lson].cheng *= a[k].cheng;
    		a[lson].cheng %= p;
    		a[rson].cheng *= a[k].cheng;
    		a[rson].cheng %= p;
    		a[lson].jia = (a[lson].jia * a[k].cheng + a[k].jia) % p;
    		a[rson].jia = (a[rson].jia * a[k].cheng + a[k].jia) % p;
    		a[k].cheng = 1;
    		a[k].jia = 0;
    	}
    	return;
    }
    
    void change1(int k)
    {
    	if(opl <= a[k].l && opr >= a[k].r)
    	{
    		a[k].cheng *= opx;
    		a[k].cheng %= p;
    		a[k].jia *= opx;
    		a[k].jia %= p;
    		a[k].sum = (a[k].sum * opx) % p;
    		return;
    	}
    	down(k);
    	int mid = a[k].l + a[k].r >> 1;
    	if(opl <= mid)change1(lson);
    	if(opr > mid)change1(rson);
    	a[k].sum = a[lson].sum + a[rson].sum;
    	a[k].sum %= p;
    	return;
    }
    
    void change2(int k)
    {
    	if(opl <= a[k].l && opr >= a[k].r)
    	{
    		a[k].jia += opx;
    		a[k].jia %= p;
    		a[k].sum += (a[k].r - a[k].l + 1) * opx;
    		a[k].sum %= p;
    		return;
    	}
    	down(k);
    	int mid = (a[k].l + a[k].r) >> 1;
    	if(opl <= mid)change2(lson);
    	if(opr > mid)change2(rson);
    	a[k].sum = a[lson].sum + a[rson].sum;
    	a[k].sum %= p;
    	return;
    }
    
    void query(int k)
    {
    	if(opl <= a[k].l && opr >= a[k].r)
    	{
    		ans += a[k].sum;
    		ans %= p;
    		return;
    	}
    	down(k);
    	int mid = (a[k].l + a[k].r) >> 1;
    	if(opl <= mid)query(lson);
    	if(opr > mid)query(rson);
    	return;
    }
    
    signed main()
    {
    	n = read(),p = read();
    	build(1,1,n);
    	m = read();
    	for(register int i = 1;i <= m;++ i)
    	{
    		int qwq = read();
    		if(qwq == 1)
    		{
    			opl = read(),opr = read(),opx = read();
    			change1(1);
    		}
    		else
    		if(qwq == 2)
    		{
    			opl = read(),opr = read(),opx = read();
    			change2(1);
    		}
    		else
    		{
    			opl = read(),opr = read();
    			ans = 0;
    			query(1);
    			cout << ans % p << endl;
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    c# udp局域网通信
    wpf 空白汉字占位符
    直角三角形知道变长求夹角
    windowsphone 的IsolatedStorageSettings存储类型
    WPFUIElement的Background的问题
    oracle外表
    oracle安装
    数据库ddl,dml,dcl
    OLTP与OLAP的介绍
    四种XML解析方式详解
  • 原文地址:https://www.cnblogs.com/acioi/p/11843305.html
Copyright © 2011-2022 走看看