Transformation

Time Limit: 15000/8000 MS (Java/Others)    Memory Limit: 65535/65536 K (Java/Others)
Total Submission(s): 3830    Accepted Submission(s): 940

Problem Description
Yuanfang is puzzled with the question below: 
There are n integers, a1, a2, …, an. The initial values of them are 0. There are four kinds of operations.
Operation 1: Add c to each number between ax and ay inclusive. In other words, do transformation ak<---ak+c, k = x,x+1,…,y.
Operation 2: Multiply c to each number between ax and ay inclusive. In other words, do transformation ak<---ak×c, k = x,x+1,…,y.
Operation 3: Change the numbers between ax and ay to c, inclusive. In other words, do transformation ak<---c, k = x,x+1,…,y.
Operation 4: Get the sum of p power among the numbers between ax and ay inclusive. In other words, get the result of axp+ax+1p+…+ay p.
Yuanfang has no idea of how to do it. So he wants to ask you to help him. 
 
Input
There are no more than 10 test cases.
For each case, the first line contains two numbers n and m, meaning that there are n integers and m operations. 1 <= n, m <= 100,000.
Each the following m lines contains an operation. Operation 1 to 3 is in this format: "1 x y c" or "2 x y c" or "3 x y c". Operation 4 is in this format: "4 x y p". (1 <= x <= y <= n, 1 <= c <= 10,000, 1 <= p <= 3)
The input ends with 0 0.
 
Output
For each operation 4, output a single integer in one line representing the result. The answer may be quite large. You just need to calculate the remainder of the answer when divided by 10007.
 
Sample Input
5 5
3 3 5 7
1 2 4 4
4 1 5 2
2 2 5 8
4 3 5 3
0 0
 
Sample Output
307
7489
 
Source
 
 
 
题目大意:开始有n数全为0的序列。
现在让你进行区间操作,操作1:给区间ui,vi每个数加wi。
           操作2:给区间ui,vi每个数乘wi
           操作3:给区间ui,vi每个数赋值为wi
           操作4:查询区间ui,vi的ci次方和。       ci取值1,2,3 结果取模。
 
解题思路:很明显是线段树操作,但是这个线段树比较复杂。。。(TM写了1天半,弱就是弱)。首先我们考虑由于需要有三种不同的结果,1次方,2次方,3次方,所以我们需要维护出来3个结果,sum1,sum2,sum3分别表示1次方和,2次方和,3次方和。如果上面的更新操作只有一个,次方和是可以很容易得到的。但是现在有赋值,有加和,有乘积,而且这些操作的顺序也不确定,不同的顺序的结果也不相同。所以应该确定下放标记的优先级别,我们首先应该知道,如果赋值操作,那么前边的所有加和操作与乘积操作就应该无效了,所以下放赋值操作应该优先考虑。然后就是乘积和加和操作的优先级了,这里我们考虑将每一个数表示成multi*x+add的形式,初始时multi为1,x为0,add为0。如果我们首先给一段区间加一个数b,那么让这个区间内所有的add变为b,如果我们又给这个区间乘上一个a,那么这个区间每个数都变成了a*x+b*a。如果我们首先给一段区间乘上一个数a,那么这个区间内所有的multi变为a,如果我们又给这个区间加上一个b,那么这个区间的每个数都变成了a*x+b。可以看出,两种下放顺序造成的影响在于add的不同,所以我们想让这个结果达到一个统一就应该首先让让乘积标记下放,然后左右儿子的add变为左右儿子的add*当前节点的multi+当前节点的add。左右儿子的multi变为左右儿子的multi*当前节点的multi。次方和需要经过简单推导得出。
二次方和:sigma((ai*y+w)^2)  =  y*y*sigma(ai^2) + 2*w*y*sigma(ai) + sigma(w^2)。
三次方和:sigma((ai*y+w)^3) = y^3*sigma(ai^3) + sigma(w^3) + 3*w*y^2*sigma(ai^2) + 3*w^2*y*sigma(ai)。
 
  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. #define mid (L+R)/2
  4. #define lson rt*2,L,mid
  5. #define rson rt*2+1,mid+1,R
  6. typedef long long INT;
  7. const int maxn = 120000;
  8. const int mod = 10007;
  9. struct SegTree{
  10. int add,multi,setv;
  11. int sum1,sum2,sum3;
  12. }segs[maxn*4];
  13. void PushUp(int rt,int L,int R){
  14. segs[rt].sum1 = (segs[rt*2].sum1 + segs[rt*2+1].sum1)% mod;
  15. segs[rt].sum2 = (segs[rt*2].sum2 + segs[rt*2+1].sum2)% mod;
  16. segs[rt].sum3 = (segs[rt*2].sum3 + segs[rt*2+1].sum3)% mod;
  17. }
  18. void buildtree(int rt,int L,int R){
  19. segs[rt].multi = 1;
  20. segs[rt].add = segs[rt].setv = 0;
  21. segs[rt].sum1 = segs[rt].sum2 = segs[rt].sum3 = 0;
  22. if(L == R){
  23. return ;
  24. }
  25. buildtree(lson);
  26. buildtree(rson);
  27. }
  28. void PushDown(int rt,int L,int R){
  29. if(segs[rt].setv){ //考虑下放赋值标记
  30. segs[rt*2].setv = segs[rt*2+1].setv = segs[rt].setv;
  31. segs[rt*2].add = segs[rt*2+1].add = 0;
  32. segs[rt*2].multi = segs[rt*2+1].multi = 1;
  33.  
  34. segs[rt*2].sum1 = (mid-L+1)*segs[rt].setv % mod;
  35. segs[rt*2].sum2 = (mid-L+1)*segs[rt].setv %mod *segs[rt].setv % mod;
  36. segs[rt*2].sum3 = (mid-L+1)*segs[rt].setv %mod *segs[rt].setv % mod *segs[rt].setv % mod;
  37.  
  38. segs[rt*2+1].sum1 = (R-mid)*segs[rt].setv % mod;
  39. segs[rt*2+1].sum2 = (R-mid)*segs[rt].setv % mod *segs[rt].setv % mod;
  40. segs[rt*2+1].sum3 = (R-mid)*segs[rt].setv % mod *segs[rt].setv % mod *segs[rt].setv % mod;
  41. segs[rt].setv = 0;
  42. }
  43. if(segs[rt].multi != 1 || segs[rt].add){//如果有加和标记或者乘积标记
  44. segs[rt*2].add = (segs[rt].multi * segs[rt*2].add %mod + segs[rt].add) % mod;
  45. segs[rt*2].multi = segs[rt].multi * segs[rt*2].multi % mod;
  46. int sum1, sum2 ,sum3;
  47. //一次方和
  48. sum1 = (segs[rt*2].sum1*segs[rt].multi %mod + (mid-L+1)*segs[rt].add %mod) % mod;
  49. //平方和
  50. sum2 = (segs[rt*2].sum2*segs[rt].multi %mod *segs[rt].multi %mod + 2*segs[rt].add * segs[rt].multi %mod *segs[rt*2].sum1 %mod + (mid-L+1)*segs[rt].add %mod *segs[rt].add %mod ) % mod;
  51. //三次方和
  52. sum3 = segs[rt*2].sum3*segs[rt].multi %mod *segs[rt].multi %mod *segs[rt].multi %mod;
  53. sum3 = (sum3 + 3*segs[rt].add*segs[rt].multi %mod *segs[rt].multi %mod *segs[rt*2].sum2 %mod) % mod;
  54. sum3 = (sum3 + 3*segs[rt].add*segs[rt].add %mod *segs[rt].multi %mod *segs[rt*2].sum1 %mod ) % mod;
  55. sum3 = (sum3 + (mid-L+1)*segs[rt].add %mod *segs[rt].add %mod *segs[rt].add %mod ) % mod;
  56. segs[rt*2].sum1 = sum1;
  57. segs[rt*2].sum2 = sum2;
  58. segs[rt*2].sum3 = sum3;
  59. //同理,更新右儿子
  60. segs[rt*2+1].add = (segs[rt*2+1].add*segs[rt].multi %mod + segs[rt].add) % mod;
  61. segs[rt*2+1].multi = segs[rt*2+1].multi * segs[rt].multi % mod;
  62. sum1 = (segs[rt*2+1].sum1*segs[rt].multi %mod + (R-mid)*segs[rt].add %mod) % mod;
  63. sum2 = (segs[rt*2+1].sum2*segs[rt].multi %mod *segs[rt].multi %mod + 2*segs[rt].add*segs[rt].multi %mod *segs[rt*2+1].sum1 %mod + (R-mid)*segs[rt].add %mod *segs[rt].add %mod) % mod;
  64.  
  65. sum3 = segs[rt*2+1].sum3*segs[rt].multi %mod *segs[rt].multi %mod *segs[rt].multi %mod;
  66. sum3 = (sum3 + 3*segs[rt].add*segs[rt].multi %mod *segs[rt].multi %mod *segs[rt*2+1].sum2 %mod) % mod;
  67. sum3 = (sum3 + 3*segs[rt].add*segs[rt].add %mod *segs[rt].multi %mod *segs[rt*2+1].sum1 %mod ) % mod;
  68. sum3 = (sum3 + (R-mid)*segs[rt].add %mod *segs[rt].add %mod *segs[rt].add %mod ) % mod;
  69.  
  70. segs[rt*2+1].sum1 = sum1;
  71. segs[rt*2+1].sum2 = sum2;
  72. segs[rt*2+1].sum3 = sum3;
  73. segs[rt].add = 0;
  74. segs[rt].multi = 1;
  75. }
  76. }
  77. void Update(int rt,int L,int R,int l_ran,int r_ran,int c,int typ){
  78. if(l_ran <= L&&R <= r_ran){
  79. if(typ == 1){ //加和
  80. segs[rt].add = (segs[rt].add + c)%mod;
  81. segs[rt].sum3 = (segs[rt].sum3 + (R-L+1)*c %mod *c %mod *c %mod + 3*c %mod *segs[rt].sum2 %mod + 3*c %mod *c %mod *segs[rt].sum1 %mod ) % mod;
  82. segs[rt].sum2 = (segs[rt].sum2 + (R-L+1)*c %mod *c %mod + 2*segs[rt].sum1 %mod *c %mod ) % mod;
  83. segs[rt].sum1 = ((R-L+1)*c %mod + segs[rt].sum1) % mod;
  84. }else if(typ == 2){ //乘积
  85. //乘积对当前节点的和跟乘都有影响
  86. segs[rt].add = segs[rt].add * c % mod;
  87. segs[rt].multi = segs[rt].multi * c % mod;
  88.  
  89. segs[rt].sum1 = segs[rt].sum1 * c % mod;
  90. segs[rt].sum2 = segs[rt].sum2 * c %mod *c %mod;
  91. segs[rt].sum3 = segs[rt].sum3 *c %mod *c %mod *c % mod;
  92. }else{ //赋值
  93. segs[rt].setv = c;
  94. segs[rt].multi = 1;
  95. segs[rt].add = 0;
  96. segs[rt].sum1 = c*(R-L+1) % mod;
  97. segs[rt].sum2 = c*(R-L+1) % mod*c % mod;
  98. segs[rt].sum3 = c*(R-L+1) % mod*c % mod *c %mod ;
  99. }
  100. return ;
  101. }
  102. PushDown(rt,L,R);
  103. if(l_ran <= mid)
  104. Update(lson,l_ran,r_ran,c,typ);
  105. if(r_ran > mid)
  106. Update(rson,l_ran,r_ran,c,typ);
  107. PushUp(rt,L,R);
  108. }
  109. int query(int rt,int L,int R,int l_ran,int r_ran,int pw){
  110. if(l_ran <= L&&R <= r_ran){
  111. if(pw == 1){
  112. return segs[rt].sum1;
  113. }else if(pw == 2){
  114. return segs[rt].sum2;
  115. }else{
  116. return segs[rt].sum3;
  117. }
  118. }
  119. PushDown(rt,L,R);
  120. int ret = 0;
  121. if(l_ran <= mid){
  122. ret = (ret + query(lson,l_ran,r_ran,pw)) % mod;
  123. }
  124. if(r_ran > mid){
  125. ret = (ret + query(rson,l_ran,r_ran,pw)) % mod;
  126. }
  127. return ret;
  128. }
  129. int main(){
  130. int n,m;
  131. while(scanf("%d%d",&n,&m)!=EOF&&(n+m)){
  132. int c,u,v,w;
  133. buildtree(1,1,n);
  134. for(int i = 1; i <= m; i++){
  135. scanf("%d%d%d%d",&c,&u,&v,&w);
  136. if(c == 4){
  137. int res = query(1,1,n,u,v,w);
  138. printf("%d\n",res);
  139. }else {
  140. Update(1,1,n,u,v,w,c);
  141. }
  142. }
  143. }
  144. return 0;
  145. }

  

 
 

HDU 4578——Transformation——————【线段树区间操作、确定操作顺序】的更多相关文章

  1. hdu 4578 Transformation 线段树多种操作裸题

    自己写了一个带结构体的WA了7.8次 但是测了几组小数据都对..感觉问题应该出在模运算那里.写完这波题解去对拍一下. 以后线段树绝不写struct!一般的struct都带上l,r 但是一条线段的长度确 ...

  2. HDU 4578 Transformation --线段树,好题

    题意: 给一个序列,初始全为0,然后有4种操作: 1. 给区间[L,R]所有值+c 2.给区间[L,R]所有值乘c 3.设置区间[L,R]所有值为c 4.查询[L,R]的p次方和(1<=p< ...

  3. hdu 4578 Transformation 线段树

    没什么说的裸线段树,注意细节就好了!!! 代码如下: #include<iostream> #include<stdio.h> #include<algorithm> ...

  4. hdu 4031 attack 线段树区间更新

    Attack Time Limit: 5000/3000 MS (Java/Others)    Memory Limit: 65768/65768 K (Java/Others)Total Subm ...

  5. HDU 3308 (线段树区间合并)

    http://acm.hdu.edu.cn/showproblem.php?pid=3308 题意: 两个操作  : 1 修改 单点  a 处的值. 2 求出 区间[a,b]内的最长上升子序列. 做法 ...

  6. HDU 3308 LCIS (线段树区间合并)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3308 题目很好懂,就是单点更新,然后求区间的最长上升子序列. 线段树区间合并问题,注意合并的条件是a[ ...

  7. hdu 5023(线段树区间染色,统计区间内颜色个数)

    题目描述:区间染色问题,统计给定区间内有多少种颜色? 线段树模板的核心是对标记的处理 可以记下沿途经过的标记,到达目的节点之后一块算,也可以更新的时候直接更新到每一个节点 Lazy操作减少修改的次数( ...

  8. Bzoj 1798: [Ahoi2009]Seq 维护序列seq(线段树区间操作)

    1798: [Ahoi2009]Seq 维护序列seq Time Limit: 30 Sec Memory Limit: 64 MB Description 老师交给小可可一个维护数列的任务,现在小可 ...

  9. LCIS HDU - 3308 (线段树区间合并)

    LCIS HDU - 3308 Given n integers. You have two operations: U A B: replace the Ath number by B. (inde ...

  10. POJ 2528 ——Mayor's posters(线段树+区间操作)

    Time limit 1000 ms Memory limit 65536 kB Description The citizens of Bytetown, AB, could not stand t ...

随机推荐

  1. windows下部署icescrum

    软件151  卢炜杰 一.安装JDK 1.下载JDK 地址:http://www.oracle.com/technetwork/java/javaee/downloads/index.html 选择相 ...

  2. Ground Truth

    ground truth就是参考标准,一般用来做误差量化.比方说要根据历史数据预测某一时间的温度,ground truth就是那个时间的真实温度.error就是(predicted temperatu ...

  3. Python3中开发目录的引用

    Python3中开发目录的引用 import os,sys BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) ...

  4. loj #2026. 「JLOI / SHOI2016」成绩比较

    #2026. 「JLOI / SHOI2016」成绩比较   题目描述 THU 的 G 系中有许许多多的大牛,比如小 R 的室友 B 神.B 神已经厌倦了与其他的同学比较 GPA(Grade Poin ...

  5. apache2.4.X虚拟主机配置

    1,用记事本打开apache目录下httpd文件(如:D:\wamp\bin\apache\apache2.2.8\conf),找到如下模块       # Virtual hosts     #In ...

  6. 阿里云linux安装jmeter并进行压测

    一.阿里云linux安装JDK 1.下载安装JDK jdk官网,选择linux版本,下载并保存. (一)yum安装 安装epel的yumyuan yum install epel-release -y ...

  7. Linux安装vim编辑器

    1.ubuntu系统:普通用户下输入命令:sudo apt-get install vim-gtk (注:出现E: Unable to locate package则将命令改成sudo apt-get ...

  8. Laplace(拉普拉斯)算子

    [摘要] Laplace算子作为边缘检测之一,和Sobel算子一样也是工程数学中常用的一种积分变换,属于空间锐化滤波操作.拉普拉斯算子(Laplace Operator)是n维欧几里德空间中的一个二阶 ...

  9. Express全系列教程之(十):jade模板引擎

    一.前言 随着前端业务的不断发展,页面交互逻辑的不断提高,让数据和界面实现分离渐渐被提了出来.JavaScript的MVC思想也流行了起来,在这种背景下,基于node.js的模板引擎也随之出现. 什么 ...

  10. hdu6441 Find Integer 求勾股数 费马大定理

    题目传送门 题目大意: 给出a和n,求满足的b和c. 思路: 数论题目,没什么好说的. 根据费马大定理,当n>2时不存在正整数解. 当n=0或者1时特判一下就可以了,也就是此时变成了一个求勾股数 ...