用指针写线段树(维护乘法)

今天肖神给我讲课,讲了一个用指针写的线段树,写起来比数组复杂,但是貌似动态开点操作好像简单一些。之前我也写过用指针的数据结构,所以理解起来不是很难。

题目描述

如题,已知一个数列,你需要进行下面三种操作:

1.将某区间每一个数乘上x

2.将某区间每一个数加上x

3.求出某区间每一个数的和
输入输出格式
输入格式:

第一行包含三个整数N、M、P,分别表示该数列数字的个数、操作的总个数和模数。

第二行包含N个用空格分隔的整数,其中第i个数字表示数列第i项的初始值。

接下来M行每行包含3或4个整数,表示一个操作,具体如下:

操作1: 格式:1 x y k 含义:将区间[x,y]内每个数乘上k

操作2: 格式:2 x y k 含义:将区间[x,y]内每个数加上k

操作3: 格式:3 x y 含义:输出区间[x,y]内每个数的和对P取模所得的结果

输出格式:

输出包含若干行整数,即为所有操作3的结果。

输入输出样例
输入样例#1: 复制

5 5 38
1 5 4 2 3
2 1 4 1
3 2 5
1 2 4 2
2 3 5 5
3 1 4

输出样例#1: 复制

17
2

说明

时空限制:1000ms,128M

数据规模:

对于30%的数据:N<=8,M<=10

对于70%的数据:N<=1000,M<=10000

对于100%的数据:N<=100000,M<=100000

(数据已经过加强^_^)

样例说明:

故输出应为17、240 mod 38=2

直接写代码:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define duke(i,a,n) for(int i = a;i <= n;i++)
typedef long long ll;
template <class T>
void read(T &x)
{
    char c;
    bool op = 0;
    while(c = getchar(),c > '9' || c < '0')
        if(c == '-') op = 1;
    x = c - '0';
    while(c = getchar(),c >= '0' && c <= '9')
        x = x * 10 + c - '0';
    if(op == 1)
        x = -x;
}
struct node
{
    node *lch,*rch;
    int sum,mul,add;
    node()
    {
        lch = 0;
        rch = 0;
        mul = 1;
        add = 0;
    }
}*root;
int n,m,p,a[100010];
void update(node *u)
{
    u->sum = (u->lch->sum + u->rch->sum) % p;
}
void build(node *&u,int l,int r)
{
    u = new node;
    if(l == r)
    {
        u->sum = a[l];
        return;
    }
    int mid = (l + r) >> 1;
    build(u->lch,l,mid);
    build(u->rch,mid + 1,r);
    update(u);
}
void refresh(node *u,int l,int r,int mul,int add)
{
    u->sum = (ll)u->sum * mul % p;
    u->sum = (u->sum + (ll)add * (r - l + 1)) % p;
    u->mul = (ll)u->mul * mul % p;
    u->add = ((ll)u->add * mul + add) % p;
}
void push_down(node *u,int l,int r)
{
    if(u->mul != 1 || u->add != 0)
    {
        int mid = (l + r) >> 1;
        refresh(u->lch,l,mid,u->mul,u->add);
        refresh(u->rch,mid + 1,r,u->mul,u->add);
        u->mul = 1;
        u->add = 0;
    }
}
void modify(node *u,int l,int r,int ql,int qr,int mul,int add)
{
    if(l == ql && r == qr)
    {
        refresh(u,l,r,mul,add);
        return;
    }
    push_down(u,l,r);
    int mid = (l + r) >> 1;
    if(qr <= mid)
    {
        modify(u->lch,l,mid,ql,qr,mul,add);
    }
    else if(ql > mid)
    {
        modify(u->rch,mid + 1,r,ql,qr,mul,add);
    }
    else
    {
        modify(u->lch,l,mid,ql,mid,mul,add);
        modify(u->rch,mid + 1,r,mid + 1,qr,mul,add);
    }
    update(u);
}
int query(node *u,int l,int r,int ql,int qr)
{
    if(l == ql && r == qr)
    {
        return u->sum;
    }
    push_down(u,l,r);
    int mid = (l + r) >> 1;
    if(qr <= mid)
    {
        return query(u->lch,l,mid,ql,qr);
    }
    else if(ql > mid)
    {
        return query(u->rch,mid + 1,r,ql,qr);
    }
    else
    {
        return (query(u->lch,l,mid,ql,mid) + query(u->rch,mid + 1,r,mid + 1,qr)) % p;
    }
}
int main()
{
    read(n);read(m);read(p);
    duke(i,1,n)
        read(a[i]);
    build(root,1,n);
    int op,l,x,r;
    while(m--)
    {
        read(op);read(l);read(r);
        if(op == 1)
        {
            read(x);
            modify(root,1,n,l,r,x,0);
        }
        else if(op == 2)
        {
            read(x);
            modify(root,1,n,l,r,1,x);
        }
        else
        {
            printf("%d\n",query(root,1,n,l,r));
        }
    }
    return 0;
}

 

posted @ 2018-08-05 20:51  DukeLv  阅读(423)  评论(0编辑  收藏  举报