线段树(该段求段+lazy)优化,洛谷之提高历练地,提高模板-nlogn数据结构

原创 2018年04月17日 10:47:46

正文

      这个东西挺简单的吧,线段树就不细讲了,主要讲讲lazy。

      懒嘛~

      如果当前覆盖整个区间,那么我们就用lazy把它那个值记录下来,然后,如果不是完全覆盖当前区间,那么我们就把它下放,乘的话那你就用一下乘法分配律搞一下即可

#include<cstdio>
#include<cstdlib>
#include<cstring>

int n,m;
struct tree{int x,y,ls,rs;long long c,lazy;};
tree tr[200010];
int len=0;

void bt(int x,int y){
	len++;
	int i=len;
	tr[i].x=x;tr[i].y=y;
	tr[i].ls=-1;tr[i].rs=-1;
	tr[i].c=0;
	tr[i].lazy=0;
	if(x==y) return ;
	int mid=(x+y)/2;
	tr[i].ls=len+1;bt(x,mid);
	tr[i].rs=len+1;bt(mid+1,y);
}

void add(int p,int x,int y,int t){
	if(tr[p].x==x && tr[p].y==y){
		tr[p].lazy+=t;
		tr[p].c+=t*(y-x+1);
		return ;
	}
	int ls=tr[p].ls,rs=tr[p].rs;
	if(tr[p].lazy!=0){
		tr[ls].c+=tr[p].lazy*(tr[ls].y-tr[ls].x+1);
		tr[ls].lazy+=tr[p].lazy;
		tr[rs].c+=tr[p].lazy*(tr[rs].y-tr[rs].x+1);
		tr[rs].lazy+=tr[p].lazy;
		tr[p].lazy=0;
	}
	int mid=tr[tr[p].ls].y;
	if(y<=mid) add(tr[p].ls,x,y,t);
	else if(x>mid) add(tr[p].rs,x,y,t);
	else add(tr[p].ls,x,mid,t),add(tr[p].rs,mid+1,y,t);
	tr[p].c=tr[tr[p].ls].c+tr[tr[p].rs].c;
}

long long get_total(int p,int x,int y){
	if(tr[p].x==x && tr[p].y==y)
		return tr[p].c;
	int ls=tr[p].ls,rs=tr[p].rs;
	if(tr[p].lazy!=0){
		tr[ls].c+=tr[p].lazy*(tr[ls].y-tr[ls].x+1);
		tr[ls].lazy+=tr[p].lazy;
		tr[rs].c+=tr[p].l azy*(tr[rs].y-tr[rs].x+1);
		tr[rs].lazy+=tr[p].lazy;
		tr[p].lazy=0;
	}
	int mid=tr[ls].y;
	if(y<=mid) return get_total(ls,x,y);
	else if(x>mid) return get_total(rs,x,y);
	else return get_total(ls,x,mid)+get_total(rs,mid+1,y);
}


int main(){
	scanf("%d %d",&n,&m);
	bt(1,n);
	for(int i=1;i<=n;i++){
		int x;
		scanf("%d",&x);
		add(1,i,i,x);
	}
	for(int i=1;i<=m;i++){
		int t,x,y;
		scanf("%d %d %d",&t,&x,&y);
		if(t==1) {
			int op;
			scanf("%d",&op);
			add(1,x,y,op);
		}
		else printf("%lld\n",get_total(1,x,y));
	}
}

乘法的话pushdown搞一搞

#include<cstdio>
#include<cstdlib>
#define ll long long

struct node{int l,r,lc,rc;ll c,lza,lzm;}tr[400010];
ll a[100010];
int n,m,len=0;
ll p;

void bt(int l,int r)
{
    len++;int now=len;
    tr[now].l=l;tr[now].r=r;tr[now].lc=tr[now].rc=-1;tr[now].c=tr[now].lza=0;tr[now].lzm=1;
    if(l<r)
    {
        int mid=(l+r)/2;
        tr[now].lc=len+1;bt(l,mid);
        tr[now].rc=len+1;bt(mid+1,r);
        tr[now].c=(tr[tr[now].lc].c+tr[tr[now].rc].c)%p;
    }
    else if(l==r) tr[now].c=a[l];
}

void pushdown(int now)
{
    int lc=tr[now].lc,rc=tr[now].rc;
    tr[lc].lzm=tr[lc].lzm*tr[now].lzm%p;
    tr[rc].lzm=tr[rc].lzm*tr[now].lzm%p;
    tr[lc].lza=(tr[lc].lza*tr[now].lzm+tr[now].lza)%p;
    tr[rc].lza=(tr[rc].lza*tr[now].lzm+tr[now].lza)%p;
    tr[lc].c=(tr[lc].c*tr[now].lzm+tr[now].lza*(tr[lc].r-tr[lc].l+1))%p;
    tr[rc].c=(tr[rc].c*tr[now].lzm+tr[now].lza*(tr[rc].r-tr[rc].l+1))%p;
    tr[now].lza=0;
    tr[now].lzm=1;
}

void mult(int now,int l,int r,ll k)
{
    if(tr[now].l==l && tr[now].r==r)
    {
        tr[now].lzm=tr[now].lzm*k%p;
        tr[now].lza=tr[now].lza*k%p;
        tr[now].c=tr[now].c*k%p;
        return;
    }
    pushdown(now);
    int lc=tr[now].lc,rc=tr[now].rc;
    int mid=(tr[now].l+tr[now].r)/2;
    if(r<=mid) mult(lc,l,r,k);
    else if(mid+1<=l) mult(rc,l,r,k);
    else
    {
        mult(lc,l,mid,k);
        mult(rc,mid+1,r,k);
    }
    tr[now].c=(tr[lc].c+tr[rc].c)%p;
}

void add(int now,int l,int r,ll k)
{
    if(tr[now].l==l && tr[now].r==r)
    {
        tr[now].lza=(tr[now].lza+k)%p;
        tr[now].c=(tr[now].c+(r-l+1)*k)%p;
        return;
    }
    pushdown(now);
    int lc=tr[now].lc,rc=tr[now].rc;
    int mid=(tr[now].l+tr[now].r)/2;
    if(r<=mid) add(lc,l,r,k);
    else if(mid+1<=l) add(rc,l,r,k);
    else
    {
        add(lc,l,mid,k);
        add(rc,mid+1,r,k);
    }
    tr[now].c=(tr[lc].c+tr[rc].c)%p;
}

ll findsum(int now,int l,int r)
{
    if(tr[now].l==l && tr[now].r==r) return tr[now].c%p;
    pushdown(now);
    int lc=tr[now].lc,rc=tr[now].rc;
    int mid=(tr[now].l+tr[now].r)/2;
    if(r<=mid) return findsum(lc,l,r)%p;
    else if(mid+1<=l) return findsum(rc,l,r)%p;
    else return (findsum(lc,l,mid)+findsum(rc,mid+1,r))%p;
}

int main()
{
    scanf("%d %d %lld",&n,&m,&p);
    for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
    bt(1,n);
    for(int i=1;i<=m;i++)
    {
        int k,x,y;
        scanf("%d %d %d",&k,&x,&y);
        if(k==1) 
        {
            ll z;
            scanf("%lld",&z);
            mult(1,x,y,z);
        }
        if(k==2)
        {
            ll z;
            scanf("%lld",&z);
            add(1,x,y,z);
        }
        if(k==3) printf("%lld\n",findsum(1,x,y));
    }
}

版权声明: https://blog.csdn.net/Deep_Kevin/article/details/79971210

SuperGCD,洛谷之提高历练地,数论(3-5)

前话      数论就是研究整数的理论。包括公约公倍数、质数、欧拉定理和同余方程等。正文       其实数论不止那么简单正文      第一题:SuperGCD      这一题就是很烦的代码加很烦...
  • Deep_Kevin
  • Deep_Kevin
  • 2018-04-07 17:19:43
  • 10

[SDOI2009]E&D,洛谷之提高历练地,博弈论(3-6)

正题      第四题:[SDOI2009]E&amp;amp;D      这题不是如此的简单,因为它要涉及到找规律和Sg函数。      首先的,我们可以打一个表来观察之间的关系。      Sg...
  • Deep_Kevin
  • Deep_Kevin
  • 2018-04-08 13:48:45
  • 11

最长公共子序列,洛谷之提高历练地,提高模板-nlogn数据结构

正题      让你用Dp做,FFT了吧。(Fast,Fast,TLE).      n的平方明显是不行的。我们来尝试一下新的方法,我们把第一个序列从1到n来编号int x; scanf(&quot;...
  • Deep_Kevin
  • Deep_Kevin
  • 2018-04-17 10:57:14
  • 7

树状数组(改点求段) ,洛谷之提高历练地,提高模板-nlogn数据结构

正文      这题知道树状数组的肯定秒打咯~     我们首先要清楚lowbit(x)这个数组的含义,指的是,x最后的一个1及其后面的0组成的二进制数。如lowbit(1001001101100(2...
  • Deep_Kevin
  • Deep_Kevin
  • 2018-04-17 10:15:47
  • 1

树状数组(改段求点) ,洛谷之提高历练地,提高模板-nlogn数据结构

正题      该段求点看似很难,如果我们可以一次性把i到n都加上某个数就好了~~      不难想到用差分的思想,我们每次处理一下当前这个数与前面一个数的差值,那么通过统计这个数组的前缀和就可以完成...
  • Deep_Kevin
  • Deep_Kevin
  • 2018-04-17 10:30:30
  • 1

食物链,洛谷之提高历练地,并查集

正文      第二题:食物链      这题经典啊!!!我们可以想象,如果我们可以搞一个并查集来维护x的同伙,天敌和食物就好了。      我们想到了开三倍空间来维护x的天敌,同伙和食物。     ...
  • Deep_Kevin
  • Deep_Kevin
  • 2018-04-15 15:57:03
  • 15

种树,洛谷之提高历练地,堆

正题      第五题:种树      这题看上去很烦,实际上也很烦。。。      那么我们第一个想到的就是用堆维护最大值。      我们把多步拆成多个一步来求解,当k=1的时候,那么答案就是最大...
  • Deep_Kevin
  • Deep_Kevin
  • 2018-04-16 11:42:57
  • 4

跑路,洛谷之提高历练地,倍增

正题      跑路      这题看上去好像无从下手,又有重边,又有自环,但是想一想,其实都是一样的。      我们可不可以先处理一下一步可以到达的边,当然,一步可以到达当且仅当i到j的路径长度为...
  • Deep_Kevin
  • Deep_Kevin
  • 2018-04-20 14:51:22
  • 11

无线通讯网,洛谷之提高历练地,最小生成树

正题      第三题:无线通讯网      这题中的卫星电话,就指的是可以把原图分成S个联通块后,就可以互相联通。      那我们要把原图分成S个联通块,那么我们只需要选中P-S条最短的边(当然是...
  • Deep_Kevin
  • Deep_Kevin
  • 2018-04-11 09:28:35
  • 4

序列合并,洛谷之提高历练地,堆

正文      第三题:序列合并      我们很容易就可以得到一个结论,将A,B从小到大排序后,可以满足A1+B1&amp;lt;=A1+B2&amp;lt;=A1+B3...      我们也可以...
  • Deep_Kevin
  • Deep_Kevin
  • 2018-04-16 11:18:09
  • 21
收藏助手
不良信息举报
您举报文章:线段树(该段求段+lazy)优化,洛谷之提高历练地,提高模板-nlogn数据结构
举报原因:
原因补充:

(最多只允许输入30个字)