您的位置:首页 > 运维架构

【bzoj1798】【洛谷P2023】【AHOI2009】维护序列

2016-09-26 21:38 232 查看

题目描述

老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成。 有长为N的数列,不妨设为a1,a2,…,aN 。有如下三种操作形式: (1)把数列中的一段数全部乘一个值; (2)把数列中的一段数全部加一个值; (3)询问数列中的一段数的和,由于答案可能很大,你只需输出这个数模P的值。

输入输出格式

输入格式:

第一行两个整数N和P(1≤P≤1000000000)。第二行含有N个非负整数,从左到右依次为a1,a2,…,aN, (0≤ai≤1000000000,1≤i≤N)。第三行有一个整数M,表示操作总数。从第四行开始每行描述一个操作,输入的操作有以下三种形式: 操作1:“1 t g c”(不含双引号)。表示把所有满足t≤i≤g的ai改为ai×c (1≤t≤g≤N,0≤c≤1000000000)。 操作2:“2 t g c”(不含双引号)。表示把所有满足t≤i≤g的ai改为ai+c (1≤t≤g≤N,0≤c≤1000000000)。 操作3:“3 t g”(不含双引号)。询问所有满足t≤i≤g的ai的和模P的值 (1≤t≤g≤N)。 同一行相邻两数之间用一个空格隔开,每行开头和末尾没有多余空格。

输出格式:

对每个操作3,按照它在输入中出现的顺序,依次输出一行一个整数表示询问结果。

输入输出样例

输入样例#1:

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

输出样例#1:

2

35

8

说明

【样例说明】

初始时数列为(1,2,3,4,5,6,7)。

经过第1次操作后,数列为(1,10,15,20,25,6,7)。

对第2次操作,和为10+15+20=45,模43的结果是2。

经过第3次操作后,数列为(1,10,24,29,34,15,16}

对第4次操作,和为1+10+24=35,模43的结果是35。

对第5次操作,和为29+34+15+16=94,模43的结果是8。

测试数据规模如下表所示

数据编号12345678910
N=10100010001000060000700008000090000100000100000
M=10100010001000060000700008000090000100000100000
Source: Ahoi 2009

题解

仍旧是线段树^_^

这次与之前的几道题不同的是:多了区间乘!多了区间乘!多了区间乘!(重要的事情说三遍)

这次需要两个tag线段树了,空间会很多T.T

与只有区间加不同的是,这次在每次结束后要进行更新操作,把途径所有的标记顺便加在存和的线段树上。

切记,每次更新完都要%ha,才能获得长者庇护+1s。

代码见下(原谅我英语水平不佳)

My Code

/**************************************************************
Problem: 1798
User: infinityedge
Language: C++
Result: Accepted
Time:4820 ms
Memory:11448 kb
****************************************************************/

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
ll ha,itmp[100005],dat[400005],dat2[400005],dat3[400005];
int n,m,xx,yy,X,t,zz;
inline void gengx(int k,int d) {
int l = k<<1, r = k<<1|1;
dat[l]=(dat[l]*dat3[k]+(d-(d>>1))*dat2[k])%ha;
dat3[l]=dat3[l]*dat3[k]%ha;
dat2[l]=(dat2[l]*dat3[k]+dat2[k])%ha;
dat[r]=(dat[r]*dat3[k]+(d>>1)*dat2[k])%ha;
dat3[r]=dat3[r]*dat3[k]%ha;
dat2[r]=(dat2[r]*dat3[k]+dat2[k])%ha;
dat3[k]=1, dat2[k]=0;
}
inline void hebing(int k) {
dat[k]=(dat[k<<1]+dat[k<<1|1])%ha;
}
void init(int k,int l,int r) {
dat3[k]=1,dat2[k]=0;
if(l==r){
//printf("%d ",l);
dat[k]=itmp[l];
//    printf("%d\n",l);
return;
}
init(k<<1,l,(l+r)>>1);
init(k<<1|1,((l+r)>>1)+1,r);
//    printf("%d\n",l);
hebing(k);
//printf("%d\n",l);
}
void cheng(int a,int b,ll x,int k,int l,int r) {
if (b<l||r<a) return;
if (a<=l&&r<=b) {
dat[k]=(dat[k]*x)%ha;
dat2[k]=(dat2[k]*x)%ha;
dat3[k]=dat3[k]*x%ha;
return;
}
gengx(k,r-l+1);
cheng(a,b,x,k<<1,l,(l+r)>>1);
cheng(a,b,x,k<<1|1,((l+r)>>1)+1,r);
hebing(k);
}
void jia(int a,int b,ll x,int k,int l,int r) {
if (b<l||r<a)return;
if (a<=l&&r<=b){
dat[k]=(dat[k]+(r-l+1)*x)%ha;
dat3[k]%=ha;
dat2[k]=(dat2[k]+x)%ha;
return;
}
gengx(k,r-l+1);
jia(a,b,x,k<<1,l,(l+r)>>1);
jia(a,b,x,k<<1|1,((l+r)>>1)+1,r);
hebing(k);
}
ll query(int a,int b,int k,int l,int r){
if (b<l||r<a)return 0;
if (a<=l&&r<=b)return dat[k];
gengx(k,r-l+1);
ll res =(query(a,b,k<<1,l,(l+r)>>1)+query(a,b,k<<1|1,((l+r)>>1)+1,r))%ha;
hebing(k);
return res%ha;
}
int main() {
scanf("%d",&n);
scanf("%lld",&ha);
for(int i=1;i<=n;i++)scanf("%lld",&itmp[i]);
scanf("%d",&m);
init(1,1,n);
for(int i=1;i<=m;i++){
scanf("%d",&t);
scanf("%d%d",&xx,&yy);
if(t==1){
ll tt;
scanf("%lld",&tt);
cheng(xx,yy,tt,1,1,n);
}else if(t==2) {
ll tt;
scanf("%lld",&tt);
jia(xx,yy,tt,1,1,n);
}else if(t==3){
printf("%lld\n",query(xx,yy,1,1,n)%ha);
}
}
return 0;
}

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  线段树