zoukankan      html  css  js  c++  java
  • 维护序列

    https://loj.ac/problem/10129

    题目描述

      维护一个序列,有三个操作:(①)询问([l,r])区间内的所有数的和;(②)把区间([l,r])的数都乘上一个数;(③)把区间([l,r])的数都加上一个数。

    思路

      这道题就是货真价实的区间修改了。我们用两个(lazy)标记维护修改。对于一个区间([l,r]),乘上一个数相当于它们的和也乘上这个数,加上一个数(x)相当于把和加上((r-l+1)*x),维护这个标记即可。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N=1e5+10;
    struct Segment
    {
    	ll l,r;
    	ll sum,lazy1,lazy2;
    }T[N<<2];
    ll a[N],p;
    void pushup(ll k)
    {
    	T[k].sum=(T[k<<1].sum+T[k<<1|1].sum)%p;
    }
    void build(ll k,ll l,ll r)
    {
    	T[k].l=l;T[k].r=r;
    	T[k].lazy1=0;T[k].lazy2=1;
    	if(l==r)
    	{
    		T[k].sum=a[l];
    		return ;
    	}
    	int mid=l+r>>1;
    	build(k<<1,l,mid);build(k<<1|1,mid+1,r);
    	pushup(k);
    }
    void pushdown(int k)
    {
    	if(T[k].l==T[k].r)return ;
    	if(!T[k].lazy1&&T[k].lazy2==1)return ;
    	ll x=T[k].lazy1,y=T[k].lazy2;
    	T[k<<1].sum=(T[k<<1].sum*y+x*(T[k<<1].r-T[k<<1].l+1))%p;
    	T[k<<1|1].sum=(T[k<<1|1].sum*y+x*(T[k<<1|1].r-T[k<<1|1].l+1))%p;
    	T[k<<1].lazy1=(T[k<<1].lazy1*y+x)%p;
    	T[k<<1|1].lazy1=(T[k<<1|1].lazy1*y+x)%p;
    	T[k<<1].lazy2=(T[k<<1].lazy2*y)%p;
    	T[k<<1|1].lazy2=(T[k<<1|1].lazy2*y)%p;
    	T[k].lazy1=0;T[k].lazy2=1;
    }
    void add(ll k,ll l,ll r,ll v)
    {
    	if(T[k].l==l&&T[k].r==r)
    	{
    		T[k].sum=(T[k].sum+v*(r-l+1))%p;
    		T[k].lazy1=(T[k].lazy1+v)%p;
    		return ;
    	}
    	pushdown(k);
    	ll mid=T[k].l+T[k].r>>1;
    	if(r<=mid)add(k<<1,l,r,v);
    	else if(l>mid)add(k<<1|1,l,r,v);
    	else
    	{
    		add(k<<1,l,mid,v);
    		add(k<<1|1,mid+1,r,v);
    	}
    	pushup(k);
    }
    void multi(ll k,ll l,ll r,ll v)
    {
    	if(T[k].l==l&&T[k].r==r)
    	{
    		T[k].sum=(T[k].sum*v)%p;
    		T[k].lazy2=(T[k].lazy2*v)%p;
    		T[k].lazy1=(T[k].lazy1*v)%p;
    		return ;
    	}
    	pushdown(k);
    	ll mid=T[k].l+T[k].r>>1;
    	if(r<=mid)multi(k<<1,l,r,v);
    	else if(l>mid)multi(k<<1|1,l,r,v);
    	else
    	{
    		multi(k<<1,l,mid,v);
    		multi(k<<1|1,mid+1,r,v);
    	}
    	pushup(k);
    }
    ll query(ll k,ll l,ll r)
    {
    	pushdown(k);
    	if(T[k].l==l&&T[k].r==r)
    		return T[k].sum;
    	ll mid=T[k].l+T[k].r>>1;
    	if(r<=mid)return query(k<<1,l,r);
    	else if(l>mid)return query(k<<1|1,l,r);
    	else return (query(k<<1,l,mid)+query(k<<1|1,mid+1,r))%p;
    }
    
    ll read()
    {
    	ll res=0,w=1;
    	char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){res=(res<<3)+(res<<1)+(ch^48);ch=getchar();}
    	return res*w;
    }
    void write(ll x)
    {
    	if(x<0){putchar('-');x=-x;}
    	if(x>9)write(x/10);
    	putchar(x%10+'0');
    }
    void writeln(ll x)
    {
    	write(x);
    	putchar('
    ');
    }
    
    int main() 
    {
    	ll n=read();p=read();
    	for(int i=1;i<=n;i++)
    		a[i]=read();
    	build(1,1,n);
    	ll m=read();
    	while(m--)
    	{
    		int op=read();
    		if(op==1)
    		{
    			ll l=read(),r=read(),x=read();
    			multi(1,l,r,x);
    		}
    		else if(op==2)
    		{
    			ll l=read(),r=read(),x=read();
    			add(1,l,r,x);
    		}
    		else
    		{
    			ll l=read(),r=read();
    			writeln(query(1,l,r));
    		}
    //		for(int i=1;i<=16;i++)
    //			printf("%d %d %d %d
    ",i,T[i].l,T[i].r,T[i].sum);
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    webBrowser控制新窗口
    MSIL指令速 查表
    [转载]最新.NET Reactor v4.0.0.0 注册机
    如何得到webbrowser的句柄
    【C#】获取本地Cookie的问题
    visio 2007 简体中文版下载
    VMware Workstation(虚拟机) V6.0.2 Build 59824 汉化版 |
    ComponentOne Studio Enterprise 2010 v1
    [转载]MaxtoCode对.Net程序加密的原理及解密探讨三(实例解密)
    用WPF实现打印及打印预览
  • 原文地址:https://www.cnblogs.com/fangbozhen/p/11767148.html
Copyright © 2011-2022 走看看