【BZOJ2962】序列操作

Description

  有一个长度为n的序列,有三个操作1.I a b c表示将[a,b]这一段区间的元素集体增加c,2.R a b表示将[a,b]区间内所有元素变成相反数,3.Q a b c表示询问[a,b]这一段区间中选择c个数相乘的所有方案的和mod 19940417的值。

Input

  第一行两个数n,q表示序列长度和操作个数。
  第二行n个非负整数,表示序列。
  接下来q行每行输入一个操作I a b c或者 R a b或者Q a b c意义如题目描述。

Output

  对于每个询问,输出选出c个数相乘的所有方案的和mod19940417的值。

Sample Input

5 5
1 2 3 4 5
I 2 3 1
Q 2 4 2
R 1 5
I 1 3 -1
Q 1 5 1

Sample Output

40
19940397
样例说明
  做完第一个操作序列变为1 3 4 4 5。
  第一次询问结果为3*4+3*4+4*4=40。
  做完R操作变成-1 -3 -4 -4 -5。
  做完I操作变为-2 -4 -5 -4 -5。
  第二次询问结果为-2-4-5-4-5=-20。

HINT

  100%的数据n<=50000,q<=50000,初始序列的元素的绝对值<=109,I a b c中保证[a,b]是一个合法区间,|c|<=109,R a b保证[a,b]是个合法的区间。Q a b c中保证[a,b]是个合法的区间1<=c<=min(b-a+1,20)。

题解:线段树套路题。对于线段树上的每个节点都维护s[i]表示当前区间取出i个数的所有方案的和,然后区间合并的时候就是求卷积,区间取反的时候就是将奇数位取反,区间加的时候比较麻烦,用组合数搞一搞就行了。

#include <cstdio>
#include <cstring>
#include <iostream>
#define lson x<<1
#define rson x<<1|1
using namespace std;
typedef long long ll;
const ll P=19940417;
const int maxn=50010;
int n,m;
ll C[maxn][22];
int v[maxn];
char str[5];
struct node
{
ll ts;
int tf,siz;
ll a[21];
ll & operator [] (int b) {return a[b];}
node () {memset(a,0,sizeof(a)),ts=tf=siz=0;}
node operator + (node b)
{
node c;
register int i,j;
for(i=0;i<=20;i++) for(j=0;i+j<=20;j++) c[i+j]=(c[i+j]+a[i]*b[j])%P;
c.siz=siz+b.siz;
return c;
}
inline void rev()
{
for(register int i=1;i<20;i+=2) a[i]=(P-a[i])%P;
ts=(P-ts)%P,tf^=1;
}
inline void add(ll x)
{
ts=(ts+x)%P;
register int i,j;
register ll y;
for(i=min(20,siz);i;i--)
{
for(y=x,j=1;j<i;y=y*x%P,j++) a[i]=(a[i]+y*a[i-j]%P*C[siz-i+j][j])%P;
a[i]=(a[i]+C[siz][i]*y)%P;
}
}
}s[maxn<<2];
inline void pushdown(int x)
{
if(s[x].tf) s[lson].rev(),s[rson].rev(),s[x].tf=0;
if(s[x].ts) s[lson].add(s[x].ts),s[rson].add(s[x].ts),s[x].ts=0;
}
void build(int l,int r,int x)
{
if(l==r)
{
s[x].siz=s[x][0]=1,s[x][1]=v[l];
return ;
}
int mid=(l+r)>>1;
build(l,mid,lson),build(mid+1,r,rson);
s[x]=s[lson]+s[rson];
}
void up1(int l,int r,int x,int a,int b,ll c)
{
if(a<=l&&r<=b)
{
s[x].add(c);
return ;
}
pushdown(x);
int mid=(l+r)>>1;
if(a<=mid) up1(l,mid,lson,a,b,c);
if(b>mid) up1(mid+1,r,rson,a,b,c);
s[x]=s[lson]+s[rson];
}
void up2(int l,int r,int x,int a,int b)
{
if(a<=l&&r<=b)
{
s[x].rev();
return ;
}
pushdown(x);
int mid=(l+r)>>1;
if(a<=mid) up2(l,mid,lson,a,b);
if(b>mid) up2(mid+1,r,rson,a,b);
s[x]=s[lson]+s[rson];
}
node query(int l,int r,int x,int a,int b)
{
if(a<=l&&r<=b) return s[x];
pushdown(x);
int mid=(l+r)>>1;
if(b<=mid) return query(l,mid,lson,a,b);
if(a>mid) return query(mid+1,r,rson,a,b);
return query(l,mid,lson,a,b)+query(mid+1,r,rson,a,b);
}
inline int rd()
{
int ret=0,f=1; char gc=getchar();
while(gc<'0'||gc>'9') {if(gc=='-') f=-f; gc=getchar();}
while(gc>='0'&&gc<='9') ret=ret*10+gc-'0',gc=getchar();
return ret*f;
}
int main()
{
n=rd(),m=rd();
int i,j,a,b,c;
for(i=0;i<=n;i++)
{
C[i][0]=1;
for(j=1;j<=min(i,20);j++) C[i][j]=(C[i-1][j-1]+C[i-1][j])%P;
}
for(i=1;i<=n;i++) v[i]=rd()%P;
build(1,n,1);
for(i=1;i<=m;i++)
{
scanf("%s",str),a=rd(),b=rd();
if(str[0]=='I') c=rd(),up1(1,n,1,a,b,(c+P)%P);
if(str[0]=='R') up2(1,n,1,a,b);
if(str[0]=='Q') c=rd(),printf("%lld\n",(query(1,n,1,a,b).a[c]+P)%P);
}
return 0;
}//5 5 1 2 3 4 5 I 2 3 1 Q 2 4 2 R 1 5 I 1 3 -1 Q 1 5 1

【BZOJ2962】序列操作 线段树的更多相关文章

  1. 【题解】P4247 [清华集训]序列操作(线段树修改DP)

    [题解]P4247 [清华集训]序列操作(线段树修改DP) 一道神仙数据结构(DP)题. 题目大意 给定你一个序列,会区间加和区间变相反数,要你支持查询一段区间内任意选择\(c\)个数乘起来的和.对1 ...

  2. 【BZOJ-2962】序列操作 线段树 + 区间卷积

    2962: 序列操作 Time Limit: 50 Sec  Memory Limit: 256 MBSubmit: 678  Solved: 246[Submit][Status][Discuss] ...

  3. 【BZOJ-1858】序列操作 线段树

    1858: [Scoi2010]序列操作 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 1961  Solved: 991[Submit][Status ...

  4. BZOJ 1858: [Scoi2010]序列操作( 线段树 )

    略恶心的线段树...不过只要弄清楚了AC应该不难.... ---------------------------------------------------------------- #inclu ...

  5. 【bzoj1858】[Scoi2010]序列操作 线段树区间合并

    题目描述 lxhgww最近收到了一个01序列,序列里面包含了n个数,这些数要么是0,要么是1,现在对于这个序列有五种变换操作和询问操作: 0 a b 把[a, b]区间内的所有数全变成0 1 a b ...

  6. Luogu P2572 [SCOI2010]序列操作 线段树。。

    咕咕了...于是借鉴了小粉兔的做法ORZ... 其实就是维护最大子段和的线段树,但上面又多了一些操作....QWQ 维护8个信息:1/0的个数(sum),左/右边起1/0的最长长度(ls,rs),整段 ...

  7. 洛谷$P2572\ [SCOI2010]$ 序列操作 线段树/珂朵莉树

    正解:线段树/珂朵莉树 解题报告: 传送门$w$ 本来是想写线段树的,,,然后神仙$tt$跟我港可以用珂朵莉所以决定顺便学下珂朵莉趴$QwQ$ 还是先写线段树做法$QwQ$? 操作一二三四都很$eas ...

  8. bzoj1858[Scoi2010]序列操作 线段树

    1858: [Scoi2010]序列操作 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 3079  Solved: 1475[Submit][Statu ...

  9. [SCOI2010]序列操作 线段树

    ---题面--- 题解: 在考场上打的这道题,出人意料的很快就打完了?! 直接用线段树,维护几个东西: 1,lazy标记 : 表示区间赋值 2,mark标记:表示区间翻转 3,l1:前缀最长连续的1的 ...

随机推荐

  1. Django Error: That port is already in use.

    原文:http://stackoverflow.com/questions/20239232/error-that-port-is-already-in-use A more simple solut ...

  2. css中属性值继承小解

    继承:html元素可以从父元素那里继承一部分css属性,即使当前元素没有定义该属性. 1.css可以和不可以继承的属性 不可继承的:display.margin.border.padding.back ...

  3. FIFO、LRU、OPT页面调度算法及样例

    网上非常多介绍3种页面置换算法的样例和过程是不对的, 本文依据<操作系统概念>第七版对三种算法做介绍,并给出正确的样例以验证算法. 一.FIFO先进先出页面置换算法,创建一个FIFO队列来 ...

  4. mysql中实现分类汇总功能

    1.创建测试表: CREATE TABLE test_ROLLUP_1 ( StateCode ), DepCode ), SendMoney INT ); 2.插入测试语句: INSERT INTO ...

  5. atitit.提升研发效率的利器---重型框架与类库的区别与设计原则

    atitit.提升研发效率的利器---重型框架与类库的区别与设计原则 1. 框架的意义---设计的复用 1 1.1. 重型框架就是it界的重武器. 1 2. 框架 VS. 库 可视化图形化 1 2.1 ...

  6. ToStringBuilder学习(二):两种方法用法优缺点及一个问题

    研究ApacheCommon源码, 先从一个最简单的开始,即围绕Object类里的toString方法自动化实现的一系列类.         怎么来自动化地实现toString方法, 有两种:反射和手 ...

  7. python学习之sys模块

    查看python的版本 >>> sys.version_info[] sys.argv 列表对象,传入模块参数的都会放入列表中. #-*- coding: utf-8 -*- # i ...

  8. 在元素的装载数量明确的时候HashMap的大小应该如何选择。

    今天看到美团招聘给出了一道小题目,关于HashMap的性能问题.问题如下: java hashmap,如果确定只装载100个元素,new HashMap(?)多少是最佳的,why? 要回答这个问题,首 ...

  9. 一图总结C++中关于指针的那些事

    指向对象的指针.指向数据成员的指针,指向成员函数的指针: 数组即指针,数组的指针,指针数组: 指向函数的指针,指向类的成员函数的指针,指针作为函数參数,指针函数: 指针的指针,指向数组的指针:常指针. ...

  10. Oracle的REGEXP_INSTR函数简单使用方法

    REGEXP_INSTR函数让你搜索一个正則表達式模式字符串. 函数使用输入字符集定义的字符进行字符串的计算. 它返回一个整数,指示開始或结束匹配的子位置.这取决于return_option參数的值. ...