BZOJ_2962_序列操作_线段树

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)。



每个区间维护F[i]表示当c=i时这个区间的答案。

然后可以暴力合并区间的答案,上传和查询同理。

难点在于两个修改。

取相反数的操作显然只对i为奇数的F[i]取相反数,偶数不变。

区间加x时,假设从${a,b,c}$到${a+x,b+x,c+x}$,那么$(a+x)*(b+x)+(b+x)*(c+x)+(a*x)+(c*x)=ab+ac+bc+2x(a+b+c)+3x^{2}$。

有一些是我们已经知道的信息,剩下的那些x的系数是组合数,预处理出来即可。

代码:

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
#define N 50050
#define mod 19940417
#define ls p<<1
#define rs p<<1|1
int n,m,C[N][22];
struct node {
    int add,rev,s[22],siz;
    node() {memset(s,0,sizeof(s));rev=add=siz=0;}
    node operator + (const node &x) const {
        node re;
        int i,j;
        for(i=0;i<=20;i++) {
            for(j=0;i+j<=20;j++) {
                re.s[i+j]=(re.s[i+j]+1ll*s[i]*x.s[j]%mod+mod)%mod;
            }
        }
        re.siz=siz+x.siz;
        return re;
    }
    void rev_() {
        int i;
        for(i=1;i<=20;i+=2) s[i]=(mod-s[i])%mod;
    }
    void add_(int d) {
        int i,j;
        int t;
        for(i=min(siz,20);i;i--) {
            for(t=d,j=1;j<i;j++,t=1ll*t*d%mod) s[i]=(s[i]+1ll*t*s[i-j]%mod*C[siz-i+j][j]%mod)%mod;
            s[i]=(s[i]+1ll*C[siz][i]*t%mod)%mod;
        }
    }
}t[N<<2];
void pushdown(int p) {
    if(t[p].rev) {
        t[ls].rev_(); t[rs].rev_();
        t[ls].add=(mod-t[ls].add)%mod; t[rs].add=(mod-t[rs].add)%mod;
        t[ls].rev^=1; t[rs].rev^=1;
        t[p].rev=0;
    }
    if(t[p].add) {
        int d=t[p].add;
        t[ls].add_(d); t[rs].add_(d);
        t[ls].add=(t[ls].add+d)%mod; t[rs].add=(t[rs].add+d)%mod;
        t[p].add=0;
    }
}
void build(int l,int r,int p) {
    if(l==r) {
        int x;
        scanf("%d",&x);
        x=(x%mod+mod)%mod;
        t[p].s[0]=1; t[p].s[1]=x; t[p].siz=1;
        return ;
    }
    int mid=(l+r)>>1;
    build(l,mid,ls); build(mid+1,r,rs);
    t[p]=t[ls]+t[rs];
}
node query(int l,int r,int x,int y,int p) {
    if(x<=l&&y>=r) return t[p];
    pushdown(p);
    int mid=(l+r)>>1;
    if(y<=mid) return query(l,mid,x,y,ls);
    if(x>mid) return query(mid+1,r,x,y,rs);
    return query(l,mid,x,y,ls)+query(mid+1,r,x,y,rs);
}
void update(int l,int r,int x,int y,int v,int p) {
    if(x<=l&&y>=r) {
        t[p].add_(v); (t[p].add+=v)%=mod;
        return ;
    }
    pushdown(p);
    int mid=(l+r)>>1;
    if(x<=mid) update(l,mid,x,y,v,ls);
    if(y>mid) update(mid+1,r,x,y,v,rs);
    t[p]=t[ls]+t[rs];
}
void reverse(int l,int r,int x,int y,int p) {
    if(x<=l&&y>=r) {
        t[p].rev_(); t[p].rev^=1; t[p].add=(mod-t[p].add)%mod;
        return ;
    }
    pushdown(p);
    int mid=(l+r)>>1;
    if(x<=mid) reverse(l,mid,x,y,ls);
    if(y>mid) reverse(mid+1,r,x,y,rs);
    t[p]=t[ls]+t[rs];
}
char opt[10];
int main() {
    int i,x,y,z,j;
    scanf("%d%d",&n,&m);
    for(i=0;i<=n;i++) C[i][0]=C[i][i]=1;
    for(i=1;i<=n;i++) {
        int t=min(20,i);
        for(j=1;j<=t;j++) C[i][j]=(C[i-1][j]+C[i-1][j-1])%mod;
    }
    build(1,n,1);
    while(m--) {
        scanf("%s%d%d",opt,&x,&y);
        if(opt[0]!=‘R‘) scanf("%d",&z);
        if(opt[0]==‘I‘) {
            z=(z%mod+mod)%mod;
            update(1,n,x,y,z,1);
        }else if(opt[0]==‘R‘) {
            reverse(1,n,x,y,1);
        }else {
            printf("%d\n",(query(1,n,x,y,1).s[z]%mod+mod)%mod);
        }
    }
}

原文地址:https://www.cnblogs.com/suika/p/9033103.html

时间: 2024-10-11 10:04:34

BZOJ_2962_序列操作_线段树的相关文章

BZOJ_1858_[Scoi2010]序列操作_线段树

Description lxhgww最近收到了一个01序列,序列里面包含了n个数,这些数要么是0,要么是1,现在对于这个序列有五种变换操作和询问操作: 0 a b 把[a, b]区间内的所有数全变成0 1 a b 把[a, b]区间内的所有数全变成1 2 a b 把[a,b]区间内的所有数全部取反,也就是说把所有的0变成1,把所有的1变成0 3 a b 询问[a, b]区间内总共有多少个1 4 a b 询问[a, b]区间内最多有多少个连续的1 对于每一种询问操作,lxhgww都需要给出回答,聪

[bzoj4636]蒟蒻的数列_线段树

蒟蒻的数列 bzoj-4636 题目大意:给定一个序列,初始均为0.n次操作:每次讲一段区间中小于k的数都变成k.操作的最后询问全局和. 注释:$1\le n\le 4\cdot 10^4$. 想法:那个操作就是一个不好好说话的操作,说白了就是对区间的每一个数取max 然后我们对于那个序列建立分治线段树.每个操作我都把它挂在对应的log的点上. n个操作都执行完了之后我们从1号节点深搜,更新答案即可. 最后,附上丑陋的代码... ... #include <iostream> #include

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

题目链接 P2023 [AHOI2009]维护序列 解题思路 线段树板子.不难,但是...有坑.坑有多深?一页\(WA\). 由于乘法可能乘\(k=0\),我这种做法可能会使结果产生负数.于是就有了这篇题解. (详情见代码注释) AC代码 #include<stdio.h> #define min(a,b) (a>b?b:a) #define max(a,b) (a>b?a:b) typedef long long ll; int n,m; ll mod,k,a[500010];

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>

bzoj1798: [Ahoi2009]Seq 维护序列seq(线段树多重标记下传)

www.cnblogs.com/shaokele/ bzoj1798: [Ahoi2009]Seq 维护序列seq Time Limit: 30 Sec Memory Limit: 64 MB Description 老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成. 有长为N的数列,不妨设为a1,a2,-,aN .有如下三种操作形式: (1)把数列中的一段数全部乘一个值; (2)把数列中的一段数全部加一个值; (3)询问数列中的一段数的和,由于答案可能很大,你只需输出这个数模P的值

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

bzoj1798 题目描述:给定n个数的序列,有三种操作. ?????1.将一段区间乘上c ?????2.将一段区间加上c ?????3.求一段区间的和 输入格式:第一行两个整数第一行两个整数N和P(1≤P≤1000000000).第二行含有N个非负整数,从左到右依次为a1,a2,-,aN, (0≤ai≤1000000000,1≤i≤N).第三行有一个整数M,表示操作总数.从第四行开始每行描述一个操作,输入的操作有以下三种形式: 操作1:"1 t g c"(不含双引号).表示把所有满足

2333: [SCOI2011]棘手的操作[离线线段树]

2333: [SCOI2011]棘手的操作 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 2325  Solved: 909[Submit][Status][Discuss] Description 有N个节点,标号从1到N,这N个节点一开始相互不连通.第i个节点的初始权值为a[i],接下来有如下一些操作: U x y: 加一条边,连接第x个节点和第y个节点 A1 x v: 将第x个节点的权值增加v A2 x v: 将第x个节点所在的连通块的所有

敌兵布阵_区间求和问题_线段树 or 树状数组

敌兵布阵 TimeLimit: 2000/1000 MS (Java/Others)  MemoryLimit: 65536/32768 K (Java/Others) 64-bit integer IO format:%I64d Problem Description C国的死对头A国这段时间正在进行军事演习,所以C国间谍头子Derek和他手下Tidy又开始忙乎了.A国在海岸线沿直线布置了N个工兵营地,Derek和Tidy的任务就是要监视这些工兵营地的活动情况.由于采取了某种先进的监测手段,所

LibreOJ #6190. 序列查询(线段树+剪枝)

莫队貌似是过不了的,这题是我没见过的科技... 首先区间按右端点排序,然后一个扫描线,扫到某个区间右端点时候计算答案,线段树上节点的信息并不需要明确定义,我们只要求线段树做到当前扫到now时,查询[L,now]即为这一段的答案. 朴素的不加优化的做法,我们在每一个点R加进来的时候要更新1~R-1所有点,这样显然是会TLE的. 强调一遍我们只要求线段树做到当前扫到now时,查询[L,now]即为这一段的答案,因此我们记录一下更新到现在的最小的绝对值mn,对于线段树上每一节点都维护一个set,维护这