码迷,mamicode.com
首页 > 其他好文 > 详细

BZOJ1798 [Ahoi2009]Seq 维护序列seq

时间:2017-04-10 10:57:25      阅读:155      评论:0      收藏:0      [点我收藏+]

标签:lin   log   type   roo   cto   解题报告   标记   end   push   

本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作。

 

 

本文作者:ljh2000
作者博客:http://www.cnblogs.com/ljh2000-jump/
转载请注明出处,侵权必究,保留最终解释权!

 

题目链接:BZOJ1798

正解:线段树

解题报告:

  考虑在线段树上维护一个乘法和加法标记,为了方便,我们把两个标记变成一个式子:$cx+d$的形式。

  对于一次加法操作,我们的二元组相当于是$(1,add*len)$,而乘法操作则是$(c,0)$,这个标记可以直接合并,下传的时候合并一下就好了。

 

//It is made by ljh2000
//有志者,事竟成,破釜沉舟,百二秦关终属楚;苦心人,天不负,卧薪尝胆,三千越甲可吞吴。
#include <algorithm>
#include <iostream>
#include <cstring>
#include <vector>
#include <cstdio>
#include <string>
#include <queue>
#include <cmath>
#include <ctime>
#define lc root<<1
#define rc root<<1|1
#define rep(i,j,k) for(int i=j;i<=k;i++)
#define reg(i,x) for(int i=first[x];i;i=next[i])
using namespace std;
typedef long long LL;
const int MAXN = 300011;
int n,m,p;
struct node{ int l,r; LL len,c,d,sum; }a[MAXN*3];
inline void update(int root){ a[root].sum=(a[lc].sum+a[rc].sum)%p; }
inline int getint(){
    int w=0,q=0; char c=getchar(); while((c<‘0‘||c>‘9‘) && c!=‘-‘) c=getchar();
    if(c==‘-‘) q=1,c=getchar(); while (c>=‘0‘&&c<=‘9‘) w=w*10+c-‘0‘,c=getchar(); return q?-w:w;
}

inline void build(int root,int l,int r){
	a[root].l=l; a[root].r=r; a[root].len=r-l+1; a[root].c=1; a[root].d=0;
	if(l==r) { a[root].sum=getint(); return ; }
	int mid=(l+r)>>1; build(lc,l,mid); build(rc,mid+1,r);
	a[root].sum=a[lc].sum+a[rc].sum; a[root].sum%=p;//!!!
}

inline void calc(node &q,LL c,LL d){
	q.c=q.c*c%p;
	q.d=(q.d*c%p+d)%p;
	q.sum=(c/*!!!*/*q.sum%p+d/*!!!*/*q.len%p/*!!!*/)%p;
	if(q.l==q.r) q.c=1,q.d=0;
}

inline void pushdown(int root,int l,int r){
	if(l==r) { a[root].c=1; a[root].d=0; return ; }
	if(a[root].c==1 && a[root].d==0) return ;
	calc(a[lc],a[root].c,a[root].d);
	calc(a[rc],a[root].c,a[root].d);
	a[root].c=1; a[root].d=0;
}

inline void modify(int root,int l,int r,int ql,int qr,LL c,LL d){
	pushdown(root,l,r);
	if(ql<=l && r<=qr) { calc(a[root],c,d); return ; }
	int mid=(l+r)>>1;
	if(ql<=mid) modify(lc,l,mid,ql,qr,c,d);
	if(qr>mid) modify(rc,mid+1,r,ql,qr,c,d);
	update(root);
}

inline LL query(int root,int l,int r,int ql,int qr){
	pushdown(root,l,r);
	if(ql<=l && r<=qr) return a[root].sum;
	int mid=(l+r)>>1;
	if(ql>mid) return query(rc,mid+1,r,ql,qr); 
	else if(qr<=mid) return query(lc,l,mid,ql,qr);
	else return ( query(lc,l,mid,ql,qr)+query(rc,mid+1,r,ql,qr) )%p;
	update(root);
}

inline void work(){
	n=getint(); p=getint(); build(1,1,n);
	m=getint(); int type,l,r; LL cc;
	while(m--) {
		type=getint(); l=getint(); r=getint();
		if(type==1) { cc=getint(); cc%=p; modify(1,1,n,l,r,cc,0); }
		else if(type==2) { cc=getint(); cc%=p;modify(1,1,n,l,r,1,cc); }
		else printf("%lld\n",query(1,1,n,l,r));
	}
}

int main()
{
#ifndef ONLINE_JUDGE
	freopen("1798.in","r",stdin);
	freopen("1798.out","w",stdout);
#endif
    work();
    return 0;
}
//有志者,事竟成,破釜沉舟,百二秦关终属楚;苦心人,天不负,卧薪尝胆,三千越甲可吞吴。

  

BZOJ1798 [Ahoi2009]Seq 维护序列seq

标签:lin   log   type   roo   cto   解题报告   标记   end   push   

原文地址:http://www.cnblogs.com/ljh2000-jump/p/6687705.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!