BZOJ 1798 AHOI2009 Seq 维护序列 线段树

题目大意:维护一个序列,提供三种操作:

1.将区间中每个点的权值乘上一个数

2.将区间中每个点的权值加上一个数

3.求一段区间的和对p取模的值

2631的超^n级弱化版。写2631之前能够拿这个练练手。。。

线段树区间改动,让学校的大神指导了一下ZKW的区间改动方法,非常好理解,可是代码还是快不了。

回头再改改代码吧 可能是我写的太渣了

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define M 100100
using namespace std;
typedef long long ll;
struct abcd{
    ll sum,siz,add_mark,times_mark;
    void add(ll x);
    void times(ll x);
}tree[263000];
int m,n,p,q;
void abcd :: add(ll x)
{
    sum+=x*siz;
    sum%=p;
    add_mark+=x;
    add_mark%=p;
}
void abcd :: times(ll x)
{
    sum*=x;
    sum%=p;
    add_mark*=x;
    add_mark%=p;
    times_mark*=x;
    times_mark%=p;
}
void Build_Tree()
{
    int i;
    for(i=q+1;i<=q+n;i++)
    {
        scanf("%d",&tree[i].sum);
        tree[i].siz=1;
        tree[i].add_mark=0;
        tree[i].times_mark=1;
    }
    for(i=q-1;i;i--)
    {
        tree[i].sum=tree[i<<1].sum+tree[i<<1|1].sum;
        tree[i].sum%=p;
        tree[i].siz=tree[i<<1].siz+tree[i<<1|1].siz;
        tree[i].add_mark=0;
        tree[i].times_mark=1;
    }
}
int stack[M],top;
void Push_Down(int x)
{
    if(x>=q)
        return ;
    if(tree[x].times_mark^1)
    {
        tree[x<<1  ].times(tree[x].times_mark);
        tree[x<<1|1].times(tree[x].times_mark);
        tree[x].times_mark=1;
    }
    if(tree[x].add_mark)
    {
        tree[x<<1  ].add(tree[x].add_mark);
        tree[x<<1|1].add(tree[x].add_mark);
        tree[x].add_mark=0;
    }
}
void Push_Down(int x,int y)
{
    for(x+=q-1,y+=q+1;x^y;x>>=1,y>>=1)
        stack[++top]=x,stack[++top]=y;
    for(;x;x>>=1)
        stack[++top]=x;
    while(top)
        Push_Down(stack[top--]);
}
void Add(int x,int y,ll z)
{
    for(x+=q-1,y+=q+1;x^y^1;x>>=1,y>>=1)
    {
        if(~x&1)tree[x^1].add(z);
        if( y&1)tree[y^1].add(z);
    }
}
void Times(int x,int y,ll z)
{
    for(x+=q-1,y+=q+1;x^y^1;x>>=1,y>>=1)
    {
        if(~x&1)tree[x^1].times(z);
        if( y&1)tree[y^1].times(z);
    }
}
void Push_Up(int x)
{
    if(x>=q)
        return ;
    tree[x].sum=tree[x<<1].sum+tree[x<<1|1].sum;
    tree[x].sum%=p;
}
void Push_Up(int x,int y)
{
    for(x+=q-1,y+=q+1;x^y;x>>=1,y>>=1)
        Push_Up(x),Push_Up(y);
    for(;x;x>>=1)
        Push_Up(x);
}
ll Get_Ans(int x,int y)
{
    int re=0;
    for(x+=q-1,y+=q+1;x^y^1;x>>=1,y>>=1)
    {
        if(~x&1)re+=tree[x^1].sum,re%=p;
        if( y&1)re+=tree[y^1].sum,re%=p;
    }
    return re;
}
int main()
{
    int i,x,y,c;
    ll z;
    cin>>n>>p;
    for(q=1;q<=n+1;q<<=1);
    Build_Tree();
    cin>>m;
    for(i=1;i<=m;i++)
    {
        scanf("%d",&c);
        if(c==1)
        {
            scanf("%d%d%lld",&x,&y,&z);
            Push_Down(x,y);
            Times(x,y,z);
            Push_Up(x,y);
        }
        else if(c==2)
        {
            scanf("%d%d%lld",&x,&y,&z);
            Push_Down(x,y);
            Add(x,y,z);
            Push_Up(x,y);
        }
        else
        {
            scanf("%d%d",&x,&y);
            Push_Down(x,y);
            printf("%lld\n", Get_Ans(x,y) );
        }
    }
}
时间: 2024-08-07 04:21:45

BZOJ 1798 AHOI2009 Seq 维护序列 线段树的相关文章

bzoj 1798: [Ahoi2009]Seq 维护序列seq 线段树 区间乘法区间加法 区间求和

1798: [Ahoi2009]Seq 维护序列seq Time Limit: 1 Sec  Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/problem.php?id=1798 Description 老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成. 有长为N的数列,不妨设为a1,a2,…,aN .有如下三种操作形式: (1)把数列中的一段数全部乘一个值; (2)把数列中的一段数全部加一个值; (3)询问数列

bzoj 1798 [Ahoi2009]Seq 维护序列seq(线段树+传标)

[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1798 [题意] 给定一个序列,要求提供区间乘/加,以及区间求和的操作 [思路] 线段树+传标. 下传标记的方式可以类比这里 click here [代码] 1 #include<set> 2 #include<cmath> 3 #include<queue> 4 #include<vector> 5 #include<cstdio>

BZOJ 1798 [Ahoi2009]Seq 维护序列seq 线段树

题意:链接 方法:线段树 解析: 俩标记sb题 更新乘的时候更新加 完了 代码: #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define lson l,mid,rt<<1 #define rson mid+1,r,rt<<1|1 #define N 100010 using namespace std; typedef

bzoj 1798 [Ahoi2009]Seq 维护序列seq

原题链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1798 线段树区间更新: 1. 区间同同时加上一个数 2. 区间同时乘以一个数 1 #include<algorithm> 2 #include<iostream> 3 #include<cstdlib> 4 #include<cstdio> 5 #define lc root<<1 6 #define rc root<<1|1

BZOJ 1798: [Ahoi2009]Seq 维护序列seq (线段树乘法加法的混合操作)

 题目:点击打开链接 大意:一个数组,三个操作,第一种是区间[a,b]每个数乘乘,第二种是区间[a,b]每个数加c,第三种是查询[a,b]区间的和并对p取摸. 两种操作就不能简单的只往下传标记.每次传乘法标记时,要把加法标记同时乘上乘法标记,例如某个区间先进来一个加法标记add,之后又进来一个乘法标记mul. 那么结果为(x + add) * mul = x * mul + add * mul.这样向下传标记的时候就相对独立.递归边界更新加法标记之前先乘上该节点的mul,左右儿子down的时

bzoj 1798 [Ahoi2009]Seq 维护序列seq ——线段树

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1798 先乘后加,就可给加法标记乘上乘法标记. 注意可能有 *0 的操作,所以 pshd 时不是 cg[ cr ]>1 而是 cg[ cr ]!=1 . #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define ll long long #de

1798: [Ahoi2009]Seq 维护序列seq

1798: [Ahoi2009]Seq 维护序列seq Time Limit: 30 Sec  Memory Limit: 64 MBSubmit: 5886  Solved: 2087[Submit][Status][Discuss] Description 老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成. 有长为N的数列,不妨设为a1,a2,…,aN .有如下三种操作形式: (1)把数列中的一段数全部乘一个值; (2)把数列中的一段数全部加一个值; (3)询问数列中的一段数的和

【BZOJ】1798: [Ahoi2009]Seq 维护序列seq(线段树)

http://www.lydsy.com/JudgeOnline/problem.php?id=1798 之前写了个快速乘..........................20多s...... 还好1a.. 那么本题就是维护两个tag即可.和上一题一样. #include <cstdio> #include <cstring> #include <cmath> #include <string> #include <iostream> #inc

bzoj1798: [Ahoi2009]Seq 维护序列seq 2011-12-20

1798: [Ahoi2009]Seq 维护序列seq Time Limit: 30 Sec  Memory Limit: 64 MB Submit: 497  Solved: 203 [Submit][Status][Discuss] Description 老 师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成. 有长为N的数列,不妨设为a1,a2,…,aN .有如下三种操作形式: (1)把数列中的一段数全部乘一个值; (2)把数列中的一段数全部加一个值; (3)询问数列中的一段数的