zoukankan      html  css  js  c++  java
  • P3373 【模板】线段树 2

    内容有些肤浅,以后会深入证明,先挖好坑

    题目链接

    P3373 【模板】线段树 2

    思路

    这题乍一看觉得好难啊,然后我们来仔细分析一下题目

    题目说有两种修改操作

    1.区间加某一值
    2.区间乘某一值

    首先想到的思路一定是打两个(lazymark)
    在这两个操作有先后,我(ri),那么我们就应该来仔细看一下先后顺序对程序的影响

    顺序无非就是两种:

    1.先乘后加
    先乘后加和数学一样,所以我们来先看一下这种
    $tree[ls].date=(tree[ls].date imes tree[x].cheng % p+tree[x].jia imes (r-l+1) % p) % p ( 如此看来我们改变)cheng(的值时,只需要把)jia(去乘一下)cheng$就行了
    这样来看好像很对.........其实就是很对

    2.先加后乘
    那么我们来看一下这个
    $tree[ls].date=(tree[ls].date+ tree[x].jia)cdot tree[root].cheng % p ( 这样子的化就没法向上面的代码一样更新)cheng(时去维护)jia$了

    看完这里就没什么难的了,就是要写两个(update)去分别维护(cheng,jia)两个(lazymark)

    上面的代码显示不全,就放张图吧

    口胡

    来详细解释(口胡)一波:
    以下解释不针对题目只是口胡一波

    现在我们要对区间([l,r])进行一坨的加和乘的操作

    先把它看成加法优先的情况

    ((sum+lazy_{jia}) imes lazy_{cheng})

    很容易看出来
    如果我更新了$ lazy_{cheng}(那么)lazy_{jia}$也要改变所以我们变形一下

    ((sum imes lazy_{cheng})+lazy_{jia}*lazy_{cheng})

    (sjpnb=lazy_{jia}*lazy_{cheng})

    那么就变成了;

    ((sum imes lazy_{cheng})+sjpnb)

    如此来看(lazy_{cheng})改变就不会导致(lazy_{jia})变了
    我们把(sjpnb)看成(lazy_{jia})不就ok了?

    口胡完成有什么错误请见谅,毕竟人家是菜鸡吗

    代码

    代码写的可能复杂了些,(putdown)函数写的有点复杂了,其实没必要像我这样写

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<queue>
    #include<stack>
    #include<vector>
    #include<map>
    #include<string>
    #include<cstring>
    #define int long long int
    #define lowbit(x) x & -x
    const int N=100000;
    using namespace std;
    inline int read() {
    	char c = getchar();
    	int x = 0, f = 1;
    	while(c < '0' || c > '9') {
    		if(c == '-') f = -1;
    		c = getchar();
    	}
    	while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    	return x * f;
    }
    int n,m,p,a[N*4];
    struct node {
    	int date;
    	int cheng;
    	int jia;
    } tree[N*4+10];
    void pushup(int root) {
    	tree[root].date=(tree[root<<1].date+tree[root<<1|1].date)%p;
    }
    void build(int root,int l,int r) {
    	tree[root].cheng=1;
    	if(l==r) {
    		tree[root].date=a[l];
    		return ;
    	}
    	int mid=(l+r)/2;
    	build(root<<1,l,mid);
    	build(root<<1|1,mid+1,r);
    	pushup(root);
    }
    void pushdown(int x,int l,int r) {
    	int ls=x<<1,rs=x<<1|1,mid=(l+r)>>1;
    	tree[ls].date=(tree[ls].date*tree[x].cheng%p+tree[x].jia*(mid-l+1)%p)%p;
    	tree[ls].cheng=(tree[ls].cheng*tree[x].cheng)%p;
    	tree[ls].jia=(tree[ls].jia*tree[x].cheng+tree[x].jia)%p;
    	tree[rs].date=(tree[rs].date*tree[x].cheng%p+tree[x].jia*(r-(mid+1)+1)%p)%p;
    	tree[rs].cheng=(tree[rs].cheng*tree[x].cheng)%p;
    	tree[rs].jia=(tree[rs].jia*tree[x].cheng+tree[x].jia)%p;
    	tree[x].jia=0;
    	tree[x].cheng=1;
    	return;
    }
    void update_cheng(int root,int l,int r,int x,int y,int k) {
    	if(r<x || l>y) return ;
    	if(l>=x & r<=y) {
    		tree[root].date=(tree[root].date*k)%p;
    		tree[root].cheng=(tree[root].cheng*k)%p;
    		tree[root].jia=(tree[root].jia*k)%p;
    		return;
    	}
    	pushdown(root,l,r);
    	int mid=(l+r)>>1;
    	update_cheng(root<<1,l,mid,x,y,k);
    	update_cheng(root<<1|1,mid+1,r,x,y,k);
    	pushup(root);
    }
    void update_jia(int root,int l,int r,int x,int y,int k) {
    	if(r<x || l>y) return ;
    	if(l>=x & r<=y) {
    		tree[root].date=(tree[root].date+k*(r-l+1)%p)%p;
    		tree[root].jia=(tree[root].jia+k)%p;
    		return;
    	}
    	pushdown(root,l,r);
    	int mid=(l+r)>>1;
    	update_jia(root<<1,l,mid,x,y,k);
    	update_jia(root<<1|1,mid+1,r,x,y,k);
    	pushup(root);
    }
    int query(int root,int l,int r,int x,int y) {
    	if(r<x || l>y) return 0;
    	if(l>=x && r<=y) {
    		return tree[root].date;
    	}
    	pushdown(root,l,r);
    	int mid=(l+r)>>1;
    	return (query(root<<1,l,mid,x,y)+query(root<<1|1,mid+1,r,x,y))%p;
    }
    signed main() {
    	scanf("%lld %lld %lld",&n,&m,&p);
    	for(int i=1; i<=4*n; i++) tree[i].cheng=1;
    	for(int i=1; i<=n; i++) {
    		scanf("%lld",&a[i]);
    	}
    	build(1,1,n);
    	int opt,x,y,k;
    	while(m--) {
    		scanf("%lld",&opt);
    		if(opt==1) {
    			scanf("%lld %lld %lld",&x,&y,&k);
    			update_cheng(1,1,n,x,y,k);
    		}
    		if(opt==2) {
    			scanf("%lld %lld %lld",&x,&y,&k);
    			update_jia(1,1,n,x,y,k);
    		}
    		if(opt==3) {
    			scanf("%lld %lld",&x,&y);
    			cout<<query(1,1,n,x,y)%p<<endl;
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    使用阿里的EasyExcel实现表格导出功能
    推荐一款实用的java工具包---Hutool
    MySQL(二)锁机制【表级锁、页面锁、行级锁】
    MySQL(一)存储引擎
    使用redis的increment()方法实现计数器功能
    Redis缓存浅析
    Dubbo服务介绍
    SpringMVC工作执行流程详解
    GC垃圾回收机制----GC回收算法(GC机制必会知识点)
    数据结构之常见的数据结构
  • 原文地址:https://www.cnblogs.com/pyyyyyy/p/11114293.html
Copyright © 2011-2022 走看看