行星序列(AHOI2009)(线段树)

题目描述 Description

“神州“载人飞船的发射成功让小可可非常激动,他立志长大后要成为一名宇航员假期一始,他就报名参加了“小小宇航员夏令营”,在这里小可可不仅学到了丰富的宇航知识,还参与解决了一些模拟飞行中发现的问题,今天指导老师交给他一个任务,在这次模拟飞行的路线上有N个行星,暂且称它们为一个行星序列,并将他们从1至n标号,在宇宙未知力量的作用下这N个行星的质量是不断变化的,所以他们对飞船产生的引力也会不断变化,小可可的任务就是在飞行途中计算这个行星序列中某段行星的质量和,以便能及时修正飞船的飞行线路,最终到达目的地,行星序列质量变化有两种形式:

1,行星序列中某一段行星的质量全部乘以一个值

2,行星序列中某一段行星的质量全部加上一个值

由于行星的质量和很大,所以求出某段行星的质量和后只要输出这个值模P的结果即可,小可可被这个任务难住了,聪明的你能够帮他完成这个任务吗?

输入描述 Input Description

第一行两个整数N和P(1<=p<=1000000000);

第二行含有N个非负整数,从左到右依次为a1,a2,…………,an(0<=ai<=100000000,1<=i<=n),其中ai表示第i个行星的质量:

第三行有一个整数m,表示模拟行星质量变化以及求质量和等操作的总次数。从第四行开始每行描述一个操作,输入的操作有以下三种形式:

操作1:1 t g c 表示把所有满足t<=i<=g的行星质量ai改为ai*c

操作2:2 t g c 表示把所有满足t<=i<=g的行星质量ai改为ai+c

操作3:3 t g 表示输出所有满足t<=i<=g的ai的和模p的值

其中:1<=t<=g<=N,0<=c<=10000000

注:同一行相邻的两数之间用一个空格隔开,每行开头和末尾没有多余空格

输出描述 Output Description

对每个操作3,按照它在输入中出现的顺序,依次一行输出一个整数表示所求行星质量和

样例输入 Sample Input

7 43

1 2 3 4 5 6 7

5

1 2 5 5

3 2 4

2 3 7 9

3 1 3

3 4 7

样例输出 Sample Output

2

35

8

数据范围及提示 Data Size & Hint

100%的数据中,M,N<=100000

40%的数据中,M,N<=10000

题解:这个题和裸线段树唯一不同的地方在于有两种修改,其实这个也很好处理,遇到乘法就直接乘,加法的话先乘后加,注意中间的一些longlong就好了。。。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
long long p,t[1000001]={0},a[1000001]={0},lazy[1000001][5]={0};
void build(int k,int l,int r)
{
    int mid;
    if (l==r){t[k]=a[l]%p;return;};
    mid=(l+r)/2;
    build(k*2,l,mid);
    build(k*2+1,mid+1,r);
    t[k]=(t[k*2]+t[k*2+1])%p;
}
void paint(int k,int l,int r,long long m,long long c)
{
    t[k]=((t[k]*m)%p+(r-l+1)*c)%p;
    lazy[k][1]=(lazy[k][1]*m)%p;
    lazy[k][2]=((lazy[k][2]*m)%p+c)%p;
}
void pushdown(int k,int l,int r)
{
   int mid;
   mid=(l+r)/2;
   paint(k*2,l,mid,lazy[k][1],lazy[k][2]);
   paint(k*2+1,mid+1,r,lazy[k][1],lazy[k][2]);
   lazy[k][1]=1;lazy[k][2]=0;
}
void insert(int k,int l,int r,int ll,int rr,long long m,long long c)
{
    int mid;
    if (l>=ll&&r<=rr){paint(k,l,r,m,c);return;}
    mid=(l+r)/2;
    pushdown(k,l,r);
    if (ll<=mid) insert(k*2,l,mid,ll,rr,m,c);
    if (rr>mid) insert(k*2+1,mid+1,r,ll,rr,m,c);
    t[k]=(t[k*2]+t[k*2+1])%p;
}
long long qsum(int k,int l,int r,int ll,int rr)
{
   int mid;
   long long ans(0);
   if (l>=ll&&r<=rr)
     {
       t[k]%=p;
       return t[k];
     }
   mid=(l+r)/2;
   pushdown(k,l,r);
   if (ll<=mid) ans=(ans+qsum(k*2,l,mid,ll,rr))%p;
   if (rr>mid) ans=(ans+qsum(k*2+1,mid+1,r,ll,rr))%p;
   return ans;
}
int main()
{
   int n,m,c,x,y,z,kind,t,g;
   cin>>n>>p;
   long long ans(0);
   for (int i=1;i<=n;i++) scanf("%lld",&a[i]);
   build(1,1,n);
   for (int i=1;i<=500000;i++) lazy[i][1]=1;
   cin>>m;
   for (int i=1;i<=m;++i)
    {
        scanf("%d%d%d",&kind,&t,&g);
        if (kind==1)
        {
            scanf("%lld",&c);
            insert(1,1,n,t,g,c,0);
        }
        if (kind==2)
        {
            scanf("%lld",&c);
            insert(1,1,n,t,g,1,c);
        }
        if (kind==3)
        {
            ans=qsum(1,1,n,t,g)%p;
            printf("%lld\n",ans);
        }
    }
} 
时间: 2024-12-18 08:16:56

行星序列(AHOI2009)(线段树)的相关文章

ZYB&#39;s Premutation(有逆序数输出原序列,线段树)

ZYB's Premutation Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) Total Submission(s): 758    Accepted Submission(s): 359 Problem Description ZYB has a premutation P,but he only remeber the reverse log of each pr

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 (线段树)

题意 对于一个给定的序列有3种操作: 1.给一个区间的数乘c 2.给一个区间的数加c 3.查询区间和. 思路 就是普通的线段树区间更新,因为更新操作有两种,维护两个延迟标记就可以了,不过要注意乘和加在更新时相互之间的关系,在更新乘的时候之前加的数也要相应的乘,更新加的时候之前所乘的数没有改变. 代码 #include <stdio.h> #include <string.h> #include <iostream> #include <algorithm>

bzoj1798: [Ahoi2009]Seq 维护序列seq 线段树

题目传送门 这道题就是线段树 先传乘法标记再传加法 #include<cstdio> #include<cstring> #include<algorithm> #define LL long long using namespace std; const int M=400010; LL read(){ LL ans=0,f=1,c=getchar(); while(c<'0'||c>'9'){if(c=='-') f=-1; c=getchar();}

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

P2023 [AHOI2009]维护序列 (线段树区间修改查询)

题目链接:https://www.luogu.org/problemnew/show/P2023 一道裸的线段树区间修改题,懒惰数组注意要先乘后加 #include<bits/stdc++.h> using namespace std; typedef long long LL; const int maxx = 400010; LL tree[maxx],lazy1[maxx],lazy2[maxx],a[maxx],mod; int n; void build(int l,int r,in

P2023 [AHOI2009] 维护序列(线段树水题)

题目描述 老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成. 有长为N的数列,不妨设为a1,a2,…,aN .有如下三种操作形式: (1)把数列中的一段数全部乘一个值; (2)把数列中的一段数全部加一个值; (3)询问数列中的一段数的和,由于答案可能很大,你只需输出这个数模P的值. 输入输出格式 输入格式: 第一行两个整数N和P(1≤P≤1000000000).第二行含有N个非负整数,从左到右依次为a1,a2,…,aN, (0≤ai≤1000000000,1≤i≤N).第三行有一个整

数据结构(括号序列,线段树):ZJOI 2007 捉迷藏

[题目描述] Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiajia.Wind和孩子们决定在家里玩捉迷藏游戏.他们的家很大且构造很奇特,由N个屋子和N-1条双向走廊组成,这N-1条走廊的分布使得任意两个屋子都互相可达. 游戏是这样进行的,孩子们负责躲藏,Jiajia负责找,而Wind负责操纵这N个屋子的灯.在起初的时候,所有的灯都没有被打开.每一次,孩子们只会躲 藏在没有开灯的房间中,但是为了增加刺激性,孩子们会要求打开某个房间的电灯或者关闭某个房间的电灯.为了评估某一次

HDU 4521-小明序列(线段树好题)

题意: n个数字的序列,求各数位置间隔大于d的最长上升子序列 分析: 最基本的dp但是数据量大O(n^2)肯定超时 前dp[i]为的最长上升子序列是由前dp[1]---dp[i-d-1]符合条件的最大值得到,我们可以用线段树维护dp[1]---dp[i-d-1]的最大值 #include <map> #include <set> #include <list> #include <cmath> #include <queue> #include