BZOJ1798 线段树的标记合并

我原来准备做方差的。。

结果发现不会维护两个标记。。

就是操作变成一个 a*x+b ,每次维护a , b 即可

加的时候a=1 ,b=v

乘的时候a=v ,b=0

  1 #include <cstdio>
  2 const long long Maxn=100010;
  3
  4 long long a[Maxn],n,P,l,r,c,m,type;
  5 struct Node
  6 {
  7     long long mul,add,sum,len;
  8 }tree[Maxn<<2];
  9
 10 inline void Change(long long o,long long mul,long long add)
 11 {
 12     tree[o].mul=(tree[o].mul*mul)%P;
 13     tree[o].add=(tree[o].add*mul+add)%P;
 14     tree[o].sum=(tree[o].sum*mul+tree[o].len*add)%P;
 15 }
 16 inline void push_down(long long o)
 17 {
 18     Change(o<<1,tree[o].mul,tree[o].add);
 19     Change(o<<1|1,tree[o].mul,tree[o].add);
 20     tree[o].mul=1; tree[o].add=0;
 21 }
 22 inline void push_up(long long o)
 23 {
 24     tree[o].sum=(tree[o<<1].sum+tree[o<<1|1].sum)%P;
 25     tree[o].len=tree[o<<1].len+tree[o<<1|1].len;
 26 }
 27 void Build(long long o,long long l,long long r)
 28 {
 29     tree[o].mul=1; tree[o].add=0;
 30     if (l==r) {tree[o].sum=a[l]; tree[o].len=1; return;}
 31     long long mid=(l+r)>>1;
 32     Build(o<<1,l,mid),Build(o<<1|1,mid+1,r);
 33     push_up(o);
 34 }
 35 void Mul(long long o,long long l,long long r,long long p,long long q,long long v)
 36 {
 37     if (l==p && r==q)
 38     {
 39         Change(o,v,0);
 40         return;
 41     }
 42     push_down(o);
 43     long long mid=(l+r)>>1;
 44     if (q<=mid) Mul(o<<1,l,mid,p,q,v);
 45     if (p>=mid+1) Mul(o<<1|1,mid+1,r,p,q,v);
 46     if (p<=mid && q>=mid+1)
 47         Mul(o<<1,l,mid,p,mid,v),Mul(o<<1|1,mid+1,r,mid+1,q,v);
 48     push_up(o);
 49 }
 50 void Add(long long o,long long l,long long r,long long p,long long q,long long v)
 51 {
 52     if (l==p && r==q)
 53     {
 54         Change(o,1,v);
 55         return;
 56     }
 57     push_down(o);
 58     long long mid=(l+r)>>1;
 59     if (q<=mid) Add(o<<1,l,mid,p,q,v);
 60     if (p>=mid+1) Add(o<<1|1,mid+1,r,p,q,v);
 61     if (p<=mid && q>=mid+1)
 62         Add(o<<1,l,mid,p,mid,v),Add(o<<1|1,mid+1,r,mid+1,q,v);
 63     push_up(o);
 64 }
 65 long long Sum(long long o,long long l,long long r,long long p,long long q)
 66 {
 67     if (l==p && r==q) return tree[o].sum;
 68     long long mid=(l+r)>>1;
 69     push_down(o);
 70     if (q<=mid) return Sum(o<<1,l,mid,p,q);
 71     if (p>=mid+1) return Sum(o<<1|1,mid+1,r,p,q);
 72     if (p<=mid && q>=mid+1)
 73         return (Sum(o<<1,l,mid,p,mid)+Sum(o<<1|1,mid+1,r,mid+1,q))%P;
 74 }
 75 int main()
 76 {
 77     // freopen("c.in","r",stdin);
 78     scanf("%lld%lld",&n,&P);
 79     for (long long i=1;i<=n;i++) scanf("%lld",&a[i]);
 80     Build(1,1,n);
 81     scanf("%lld",&m);
 82     for (long long i=1;i<=m;i++)
 83     {
 84         scanf("%lld",&type);
 85         if (type==1)
 86         {
 87             scanf("%lld%lld%lld",&l,&r,&c);
 88             Mul(1,1,n,l,r,c);
 89         }
 90         if (type==2)
 91         {
 92             scanf("%lld%lld%lld",&l,&r,&c);
 93             Add(1,1,n,l,r,c);
 94         }
 95         if (type==3)
 96         {
 97             scanf("%lld%lld",&l,&r);
 98             printf("%lld\n",Sum(1,1,n,l,r));
 99         }
100     }
101     return 0;
102 }

线段树

时间: 2024-11-09 19:55:06

BZOJ1798 线段树的标记合并的相关文章

[P2894][USACO08FEB] 酒店Hotel (线段树+懒标记下传)

题意:有 n个房间,题目给出两个操作,若 op==1,就输出最靠左的连续空房数量为 x的房间序列的最左边的序号,然后将这些房间改为入住:若 op==2,就将从 x~y的的序列全部改为空房: 解法:线段树+懒标记下传: 1.线段树:题目让在一个很长的序列操作很多次,暴力显然过不了,要用线段树优化: 2.懒标记下传:这是本题的精髓.   此题要维护的不是序列上的数值总和,而是该序列的最长连续空房的长度 sum,从该节点从左向右数最长的连续空房长度 lm,以及从该节点从右向左数最长的连续空房长度 rm

HDU 1540 &amp;&amp; POJ 2892 Tunnel Warfare (线段树,区间合并).

~~~~ 第一次遇到线段树合并的题,又被律爷教做人.TAT. ~~~~ 线段树的题意都很好理解吧.. 题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1540 http://poj.org/problem?id=2892 ~~~~ 我的代码:200ms #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #defin

线段树lazy标记??Hdu4902

Nice boat Time Limit: 30000/15000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) Total Submission(s): 335    Accepted Submission(s): 159 Problem Description There is an old country and the king fell in love with a devil. The devil al

fzu 2171 线段树 lazy标记

http://acm.fzu.edu.cn/problem.php?pid=2171      Problem 2171 防守阵地 II Accept: 73    Submit: 256Time Limit: 3000 mSec    Memory Limit : 32768 KB Problem Description 部队中总共有N个士兵,每个士兵有各自的能力指数Xi,在一次演练中,指挥部确定了M个需要防守的地点,指挥部将选择M个士兵依次进入指定地点进行防守任务,获得的参考指数即为M个士兵

POJ 3468 线段树+lazy标记

lazy标记 Time Limit:5000MS     Memory Limit:131072KB     64bit IO Format:%I64d & %I64u Submit Status Description You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. One type of operation is to add some given number to

POJ 3667 线段树的区间合并简单问题

题目大意:有一排标号1-N的房间.操作一:询问是不是有连续长度为a的空房间,有的话住进最左边(占用a个房间)操作二:将[a,a+b-1]的房间清空(腾出b个房间)思路:记录每个区间中“靠左”“靠右”“中间”的空房间线段树操作:update:区间替换query:询问满足条件的最左端点 题目链接: http://vjudge.net/problem/viewProblem.action?id=10354 题目操作: 因为这里找从最左边住起的房间,所以这里不能像常规地写query函数那样写了,终于发现

HDU 1698 Just a Hook (线段树延迟标记(lazy))

题意:有n个数初始值都为1,m个操作a,b,c,表示把区间[a,b]变为c,求最后n个数的和. 经典区间更新求和问题,需要用到延迟标记(或者说是懒惰标记),简单老说就是每次更新 的时候不要更新到底,用延迟标记使得更新延迟到下次需要更新或询问的时候. #include<cstdio> #include<stdlib.h> #include<string.h> #include<string> #include<map> #include<cm

HDU 3308 线段树(区间合并)

LCIS Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 3896    Accepted Submission(s): 1766 Problem Description Given n integers.You have two operations:U A B: replace the Ath number by B. (index

hdu-3397 Sequence operation 线段树多种标记

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=3397 题目大意: 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的长度 解题思路: 线段树多种标记. 需要处理的东西比较多: 做题的时候发现一个问题: 我的宏定义Max不可以用于函数,尤其是递归函数,这样会使得同一函数重复调用好几遍,递归函数的话更会超时. 1