zoukankan      html  css  js  c++  java
  • 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,按照它在输入中出现的顺序,依次输出一行一个整数表示询问结果。


    不得不说,这题让我对lazy的理解加深了一步
    需要考虑乘与加的优先性
    我们设sum是区间和,len为区间长,(x)代表乘上或加上的值
    tag1lazy_addtag2lazy_mul

    如果我们先加再乘,即:(sum+tag1(ast)len)(ast)tag2**
    乘法操作: (sum+tag1(ast)len)(ast)tag2(ast)x是不会有影响的,所以tar1不变,tar2相乘
    加法操作 (sum+tag1(ast)len)(ast)tag2+x(ast)len
    转化后 (sum+len(x(ackslash)tag2+tag1))(ast)tag2。所以这里的tar1+=x(ackslash)tag2,tar1不变

    但这样tar1会出现精度问题

    所以考虑先乘后加
    sum(ast)tag2 (+)tag1(ast)len
    乘法操作: (sum(ast)tag2 +tag1(*)len)(ast x)
    很容易看出我们应该
    tag1(ast)=(x),tag2(ast)=(x)
    加法操作: (sum(ast)tag2 (+)tag1*len)+x(*)len
    则只需要将 tar1+=(x),tar2 不变


    代码

    #include<bits/stdc++.h>
    #define lson rt<<1
    #define rson rt<<1|1
    using namespace std;
    const int maxn=200000+10;
    struct tag
    {
    	long long add,mul;
    }lazy[maxn<<2];
    int n,m;
    long long p;
    long long sum[maxn<<2];
    long long res=0;
    inline long long read()
    {
    	long long x=0,f=1;char ch=getchar();
    	while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch<='9'&&ch>='0'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    	return x*f;
    }
    inline void pushup(int rt)
    {
    	sum[rt]=sum[lson]+sum[rson];
    	sum[rt]%=p;
    	return;
    }
    inline void pushdown(int rt,int m)
    {
    	 sum[lson]=sum[lson]*lazy[rt].mul+lazy[rt].add*(m-(m>>1));
    	 sum[lson]%=p; 
    	 sum[rson]=sum[rson]*lazy[rt].mul+lazy[rt].add*(m>>1);
    	 sum[rson]%=p;
    	 lazy[lson].add=lazy[lson].add*lazy[rt].mul+lazy[rt].add;
    	 lazy[lson].add%=p;
    	 lazy[rson].add=lazy[rson].add*lazy[rt].mul+lazy[rt].add;
    	 lazy[rson].add%=p;
    	 lazy[lson].mul*=lazy[rt].mul;
    	 lazy[lson].mul%=p;
    	 lazy[rson].mul*=lazy[rt].mul;
    	 lazy[rson].mul%=p;
    	 lazy[rt].mul=1;
    	 lazy[rt].add=0;
    	 return;
    }
    inline void build(int l,int r,int rt)
    {
    	lazy[rt].add=0;
    	lazy[rt].mul=1;
    	if(l==r)
    	{
    		sum[rt]=read();
    		sum[rt]%=p; 
    		return;
    	}
    	int m=(l+r)>>1;
    	build(l,m,lson);
    	build(m+1,r,rson);
    	pushup(rt);
    }
    inline void update_add(int L,int R,int c,int l,int r,int rt)
    {
    	if(L<=l&&r<=R)
    	{
    		lazy[rt].add+=c;
    	    lazy[rt].add%=p;
    		sum[rt]+=c*(r-l+1);
    		sum[rt]%=p;
    		return;
    	}
    	pushdown(rt,r-l+1);
    	int m=(l+r)>>1;
    	if(L<=m)
    	update_add(L,R,c,l,m,lson);
    	if(m<R)
    	update_add(L,R,c,m+1,r,rson);
    	pushup(rt);
    }
    inline void update_mul(int L,int R,int c,int l,int r,int rt)
    {
    	if(L<=l&&r<=R)
    	{
    		lazy[rt].mul*=c;
    		lazy[rt].mul%=p;
    		lazy[rt].add*=c;
    	    lazy[rt].add%=p;
    		sum[rt]*=c;
    		sum[rt]%=p;
    		return;
    	}
    	pushdown(rt,r-l+1);
    	int m=(l+r)>>1;
    	if(L<=m)
    	update_mul(L,R,c,l,m,lson);
    	if(m<R)
    	update_mul(L,R,c,m+1,r,rson);
    	pushup(rt);
    }
    void query(int L,int R,int l,int r,int rt)
    {
    	if(L<=l&&r<=R)
    	{
    		res+=sum[rt];
    		res%=p;
    		return;
    	}
    	pushdown(rt,r-l+1);
    	int m=(l+r)>>1;
    	if(L<=m)
    	query(L,R,l,m,lson);
    	if(m<R)
    	query(L,R,m+1,r,rson);
    }
    int main()
    {
    	n=read(),p=read();
    	build(1,n,1);
    	m=read();
    	for(int i=1;i<=m;i++)
    	{
    		int op=read();
    		if(op==1)
    		{
    			int x=read(),y=read(),k=read();
    			update_mul(x,y,k,1,n,1);
    		}
    		if(op==2)
    		{
    			int x=read(),y=read(),k=read();
    			update_add(x,y,k,1,n,1);	
    		}
    		if(op==3)
    		{
    			int x=read(),y=read();res=0;
    			query(x,y,1,n,1);
    			printf("%lld
    ",res);
    		}
    	}
    	return 0;
    } 
    
  • 相关阅读:
    applycationContext.xml文件配置信息
    原生json的异步操作
    解析xm文件
    druid(德鲁伊)连接池的DataSourceUtils的写法及原生写法
    MYSQL的JDBCUtils的写法
    模拟服务器
    关于函数式接口
    浅谈树和二叉树
    &和&&的区别
    全排列问题(c语言实现)
  • 原文地址:https://www.cnblogs.com/DriverBen/p/10410701.html
Copyright © 2011-2022 走看看