[bzoj 1798][luogu p2023]Seq 线段树Seq

题目大意:

维护一个数列,支持区间乘,区间加,求区间和.

线段树题,对于乘和加操作我们可以维护一个标记.对于乘用乘法分配律分解.

代码如下:

  1 #include <cstdio>
  2 #include <cstdlib>
  3 #include <cstring>
  4 #include <algorithm>
  5 using namespace std;
  6 const int N = 100010;
  7 int inline getint()
  8 {
  9     int num = 0;char ch = getchar();for(;ch < ‘0‘ || ch > ‘9‘;ch = getchar());
 10     for(;ch >= ‘0‘ && ch <= ‘9‘;ch = getchar()) num = (num << 3) + (num << 1) + ch - ‘0‘;
 11     return num;
 12 }
 13 void putint(int x){if(x > 9)putint(x / 10);putchar(x % 10 + ‘0‘);}
 14 int sum[1 + (N << 2)],col1[1 + (N << 2)],col2[1 + (N << 2)],n,m,p;
 15 void pushup(int &x){sum[x] = (sum[x << 1] + sum[x << 1 | 1]) % p;}
 16 void build(int l,int r,int x)
 17 {
 18     col1[x] = 1;
 19     if(l == r){sum[x] = getint() % p;return;}
 20     int mid = l + r >> 1;
 21     if(l <= mid) build(l,mid,x << 1);
 22     if(r > mid) build(mid + 1,r,x << 1 | 1);
 23     pushup(x);
 24 }
 25 void pushdown(int &x,int &l,int &r)
 26 {
 27     if(col1[x] != 1)
 28     {
 29         col1[x << 1] = (long long)col1[x << 1] * col1[x] % p;
 30         col2[x << 1] = (long long)col2[x << 1] * col1[x] % p;
 31         sum[x << 1] = (long long)sum[x << 1] * col1[x] % p;
 32         col1[x << 1 | 1] = (long long)col1[x << 1 | 1] * col1[x] % p;
 33         col2[x << 1 | 1] = (long long)col2[x << 1 | 1] * col1[x] % p;
 34         sum[x << 1 | 1] = (long long)sum[x << 1 | 1] * col1[x] % p;
 35         col1[x] = 1;
 36     }
 37     if(col2[x])
 38     {
 39         col2[x << 1] = (col2[x << 1] + col2[x]) % p;
 40         sum[x << 1] = ((long long)col2[x] * ((l + r >> 1) - l + 1) % p + sum[x << 1]) % p;
 41         col2[x << 1 | 1] = (col2[x << 1 | 1] + col2[x]) % p;
 42         sum[x << 1 | 1] = ((long long)col2[x] * (r - (l + r >> 1)) % p + sum[x << 1 | 1]) % p;
 43         col2[x] = 0;
 44     }
 45 }
 46 void add(int l,int r,int root,int L,int R,int x)
 47 {
 48     if(l >= L && r <= R)
 49     {
 50         col2[root] = (col2[root] + x) % p;
 51         sum[root] = ((long long)(r - l + 1) * x % p + sum[root]) % p;
 52         return;
 53     }
 54     pushdown(root,l,r);
 55     int mid = l + r >> 1;
 56     if(L <= mid) add(l,mid,root << 1,L,R,x);
 57     if(R > mid) add(mid + 1,r,root << 1 | 1,L,R,x);
 58     pushup(root);
 59 }
 60 void mul(int l,int r,int root,int L,int R,int x)
 61 {
 62     if(l >= L && r <= R)
 63     {
 64         col1[root] = (long long)col1[root] * x % p;
 65         col2[root] = (long long)col2[root] * x % p;
 66         sum[root] = (long long)sum[root] * x % p;
 67         return;
 68     }
 69     pushdown(root,l,r);
 70     int mid = l + r >> 1;
 71     if(L <= mid) mul(l,mid,root << 1,L,R,x);
 72     if(R > mid) mul(mid + 1,r,root << 1 | 1,L,R,x);
 73     pushup(root);
 74 }
 75 int query(int l,int r,int root,int L,int R)
 76 {
 77     if(l >= L && r <= R)return sum[root];
 78     pushdown(root,l,r);
 79     int mid = l + r >> 1,ret = 0;
 80     if(L <= mid)ret = query(l,mid,root << 1,L,R);
 81     if(R > mid)ret = (ret + query(mid + 1,r,root << 1 | 1,L,R)) % p;
 82     return ret;
 83 }
 84 int main()
 85 {
 86     n = getint();p = getint();build(1,n,1);
 87     m = getint();
 88     for(int i = 1;i <= m;i++)
 89     {
 90         int opt = getint(),t,g,c;
 91         switch(opt)
 92         {
 93             case 1:
 94                 t = getint();g = getint();c = getint() % p;
 95                 mul(1,n,1,t,g,c);break;
 96             case 2:
 97                 t = getint();g = getint();c = getint() % p;
 98                 add(1,n,1,t,g,c);break;
 99             case 3:
100                 t = getint();g = getint();
101                 putint(query(1,n,1,t,g));putchar(‘\n‘);
102                 break;
103         }
104     }
105     return 0;
106 }
时间: 2024-09-30 07:27:28

[bzoj 1798][luogu p2023]Seq 线段树Seq的相关文章

bzoj 1798 双标记区间修改线段树

1 #include<bits/stdc++.h> 2 using namespace std; 3 #define MAXN 100000 4 #define M ((L+R)>>1) 5 #define lc (id<<1) 6 #define rc (id<<1|1) 7 #define LL long long 8 LL C[(MAXN<<2)+15]; 9 LL P,laz1[(MAXN<<2)+15],laz2[(MAXN

BZOJ 1835 基站选址(线段树优化DP)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1835 题意:有N个村庄坐落在一条直线上,第 i(i>1)个村庄距离第1个村庄的距离为Di.需要在这些村庄中建立不超过K个通讯基站,在第i个村庄建立基站的费用为Ci.如果在距离第i个村 庄不超过Si的范围内建立了一个通讯基站,那么就成它被覆盖了.如果第i个村庄没有被覆盖,则需要向他们补偿,费用为Wi.现在的问题是,选择基站的位 置,使得总费用最小. 思路: 另外,程序中的n=n+1,m=

BZOJ 3211 花神游历各国 线段树题解

BZOJ 3211 花神游历各国 线段树题解 3211: 花神游历各国 Time Limit: 5 Sec  Memory Limit: 128 MBSubmit: 2551  Solved: 946[Submit][Status][Discuss] Description Input Output 每次x=1时,每行一个整数,表示这次旅行的开心度 Sample Input 4 1 100 5 5 5 1 1 2 2 1 2 1 1 2 2 2 3 1 1 4 Sample Output 101

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 维护序列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

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 1858 SCOI2010 序列操作 线段树

题目大意:给定一个01序列,提供三种操作: 0:把一段区间的全部元素都变成0 1:把一段区间的全部元素都变成1 2:把一段区间内的全部元素全都取反 3:查询一段区间内1的个数 4:查询一段区间内最长的一段连续的1 首先假设没有操作4这就是bitset的水题... 多了这个,我们考虑线段树 线段树的每个节点存改动标记和翻转标记,以及该区间的信息 尽管查询的信息都是1 可是我们要连0一起保存 由于翻转后0就变成了1 1就变成了0 区间信息包含: 左端点的元素 右端点的元素 左端点開始的最长的连续元素

BZOJ 3211: 花神游历各国( 线段树 )

线段树...区间开方...明显是要处理到叶节点的 之前在CF做过道区间取模...差不多, 只有开方, 那么每个数开方次数也是有限的(0,1时就会停止), 最大的数10^9开方10+次也就不会动了.那么我们线段树多记个max就可以少掉很多不必要的操作 -------------------------------------------------------------------------------------------- #include<cstdio> #include<cs