http://acm.hdu.edu.cn/showproblem.php?pid=4578

            Transformation

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

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
 

思路:看题意可以很明显地看出是一道线段树题,也是一道很典型的线段树

题意相当明显,就不多说了,有三种操作,这三种操作顺序不一样的话得到的结果是不一样的,对于这种多操作的问题,我们要做的事尽量将多种操作合并成一种操作。

我们可将区间中的数看成是 ax+b的形式,对于加c操作,则变成 ax+b+c(b->b+c),对于乘c操作,则变成 acx+bc,(a->ac,b->bc)对于赋值c操作,则变成c,即(a->1,x->c,b->0),则我们可以在线段数中加以下标记,a,b,x分别是以上提到的变量,sum[3],表示答案,sum[0],sum[1],sum[2]分别表示1次方和,平方和,立方和。对于更新和查询操作我们用pushdown函数向下更新。对于维护平方和还有立方和的问题,我们只要将平方,立方展开再利用更新之前的值即可维护,具体方法这里不多说了

需要说明的是:每次取修改值,如果发现当前遍历区间完全在需要更新的区间内时,更新当前顶点,同时记录本次以及以前的修改操作,此时不再往后跟新。

后面pushdown时就是从这个节点读取修改信息更新后面的点。

关键代码处给出了推到公式:

#include <iostream>
#include <string.h>
#include <stdio.h>
#include <algorithm>
#define maxn 100010
#define mod 10007
#define mid ((t[p].l+t[p].r)>>1)
#define ls (p<<1)
#define rs (ls|1)
using namespace std;
struct tree
{
int l,r;
int a,b,c; //a * x + b: a为乘法系数, b为需要加的值 ; c 放重置的值
int sum[3]; //三个次方的求和
}t[maxn<<2];
void pushup(int p)
{
int i;
for(i=0;i<3;i++)
t[p].sum[i]=(t[ls].sum[i]+t[rs].sum[i])%mod;
}
void pushdown(int p)
{
if(t[p].l==t[p].r)
return;
int a=t[p].a,b=t[p].b,c=t[p].c;
if(c) //需要重置
{
t[ls].a=t[rs].a=a;
t[ls].b=t[rs].b=b;
t[ls].c=t[rs].c=c;
//sum2 = k * (a * c + b)^2 //重置后每个数相同
t[ls].sum[2]=(t[ls].r-t[ls].l+1)*(a*c%mod+b)%mod*(a*c%mod+b)%mod*(a*c%mod+b)%mod;
t[ls].sum[1]=(t[ls].r-t[ls].l+1)*(a*c%mod+b)%mod*(a*c%mod+b)%mod;
t[ls].sum[0]=(t[ls].r-t[ls].l+1)*(a*c%mod+b)%mod;
t[rs].sum[2]=(t[rs].r-t[rs].l+1)*(a*c%mod+b)%mod*(a*c%mod+b)%mod*(a*c%mod+b)%mod;
t[rs].sum[1]=(t[rs].r-t[rs].l+1)*(a*c%mod+b)%mod*(a*c%mod+b)%mod;
t[rs].sum[0]=(t[rs].r-t[rs].l+1)*(a*c%mod+b)%mod;
}
else //未重置,向下更新求和
{
t[ls].a=(t[ls].a*a)%mod;
t[ls].b=(t[ls].b*a+b)%mod; //先算乘法,再算加法,即:b = b * a + b';
t[rs].a=(t[rs].a*a)%mod;
t[rs].b=(t[rs].b*a+b)%mod;
//(av + b)^3 = a^3*v^3 + b^3 + 3a^2 * v^2 * b + 3av * b^2 //k为区间长度
// 求和为= a^3*sum2 + K * b^3 + 3a^2 * b * sum1 + 3a*b^2 * sum0
t[ls].sum[2]=(a*a%mod*a%mod*t[ls].sum[2]%mod+3*a%mod*a%mod*b%mod*t[ls].sum[1]%mod+3*a%mod*b%mod*b%mod*t[ls].sum[0]%mod+b*b%mod*b%mod*(t[ls].r-t[ls].l+1)%mod)%mod;
//(av + b)^2=a^2*v^2 + b^2 + 2*a*b*v 求和:a^2*sum1 + b^2*k + 2ab*sum1
t[ls].sum[1]=(a*a%mod*t[ls].sum[1]%mod+b*b%mod*(t[ls].r-t[ls].l+1)%mod+2*a*b%mod*t[ls].sum[0]%mod)%mod;
//av + b 求和:a*sum0 + b*k
t[ls].sum[0]=(a*t[ls].sum[0]%mod+b*(t[ls].r-t[ls].l+1)%mod)%mod; t[rs].sum[2]=(a*a%mod*a%mod*t[rs].sum[2]%mod+3*a%mod*a%mod*b%mod*t[rs].sum[1]%mod+3*a%mod*b%mod*b%mod*t[rs].sum[0]%mod+b*b%mod*b%mod*(t[rs].r-t[rs].l+1)%mod)%mod;
t[rs].sum[1]=(a*a%mod*t[rs].sum[1]%mod+b*b%mod*(t[rs].r-t[rs].l+1)%mod+2*a*b%mod*t[rs].sum[0]%mod)%mod;
t[rs].sum[0]=(a*t[rs].sum[0]%mod+b*(t[rs].r-t[rs].l+1)%mod)%mod;
}
t[p].b=t[p].c=0;
t[p].a=1;
}
void build(int p,int l,int r)
{
t[p].l=l,t[p].r=r;
t[p].a=1,t[p].b=t[p].c=0;
t[p].sum[0]=t[p].sum[1]=t[p].sum[2]=0; //全部初始化为0
if(l<r)
{
build(ls,l,mid);
build(rs,mid+1,r);
}
}
void change(int p,int l,int r,int val,int flag)
{
if(t[p].l==l&&t[p].r==r)
{
if(flag==0)//加val
{
t[p].b=(t[p].b+val)%mod;
//y = (x + v)^3 //x为原来的值
//y = x^3 + v^3 + 3 * x^2 * v + 3 * x * v^2;求和 = sum2 + v^3 + 3*sum1*v + 3*sum0*v^2
t[p].sum[2]=(t[p].sum[2]+3*val%mod*t[p].sum[1]%mod+3*val%mod*val%mod*t[p].sum[0]%mod+val*val%mod*val%mod*(t[p].r-t[p].l+1)%mod)%mod;
t[p].sum[1]=(t[p].sum[1]+val*val%mod*(t[p].r-t[p].l+1)%mod+2*val*t[p].sum[0]%mod)%mod;
t[p].sum[0]=(t[p].sum[0]+val*(t[p].r-t[p].l+1))%mod;
}
else if(flag==1) //乘以val
{
t[p].a=(t[p].a*val)%mod;
t[p].b=(t[p].b*val)%mod;
//y = (x * v)^3 = x^3 * v^3;求和 = v^3 * sum2
t[p].sum[2]=val*val%mod*val%mod*t[p].sum[2]%mod;
t[p].sum[1]=val*val%mod*t[p].sum[1]%mod;
t[p].sum[0]=val*t[p].sum[0]%mod;
}
else if(flag==2) //重置为val
{
t[p].a=1;
t[p].b=0;
t[p].c=val;
//y = (v)^3
t[p].sum[2]=(t[p].r-t[p].l+1)%mod*val%mod*val%mod*val%mod;
t[p].sum[1]=(t[p].r-t[p].l+1)%mod*val%mod*val%mod;
t[p].sum[0]=(t[p].r-t[p].l+1)*val%mod;
}
return;
}
pushdown(p);
if(l>mid)
change(rs,l,r,val,flag);
else if(r<=mid)
change(ls,l,r,val,flag);
else
{
change(ls,l,mid,val,flag);
change(rs,mid+1,r,val,flag);
}
pushup(p);
}
int query(int p,int l,int r,int flag)
{
if(t[p].l==l&&t[p].r==r)
return t[p].sum[flag];
pushdown(p);
if(l>mid)
return query(rs,l,r,flag);
else if(r<=mid)
return query(ls,l,r,flag);
else
{
return (query(ls,l,mid,flag)+query(rs,mid+1,r,flag))%mod;
}
}
int main()
{
// freopen("dd.txt","r",stdin);
int n,m;
while(scanf("%d%d",&n,&m)&&(n+m))
{
build(1,1,n);
int q,x,y,c;
while(m--)
{
scanf("%d%d%d%d",&q,&x,&y,&c);
if(q==4)
{
printf("%d\n",query(1,x,y,c-1));
}
else
{
change(1,x,y,c,q-1);
}
}
}
return 0;
}

  

30-Transformation(HDU4578)-区间线段树(复杂)的更多相关文章

  1. hdu 1540 Tunnel Warfare (区间线段树(模板))

    http://acm.hdu.edu.cn/showproblem.php?pid=1540 Tunnel Warfare Time Limit: 4000/2000 MS (Java/Others) ...

  2. BZOJ 3110 ZJOI 2013 K大数查询 树套树(权值线段树套区间线段树)

    题目大意:有一些位置.这些位置上能够放若干个数字. 如今有两种操作. 1.在区间l到r上加入一个数字x 2.求出l到r上的第k大的数字是什么 思路:这样的题一看就是树套树,关键是怎么套,怎么写.(话说 ...

  3. 【bzoj3110】[Zjoi2013]K大数查询 权值线段树套区间线段树

    题目描述 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c.如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数 ...

  4. 【BZOJ-4653】区间 线段树 + 排序 + 离散化

    4653: [Noi2016]区间 Time Limit: 60 Sec  Memory Limit: 256 MBSubmit: 107  Solved: 70[Submit][Status][Di ...

  5. UOJ222 NOI2016 区间 线段树+FIFO队列

    首先将区间按长度排序后离散化端点(这里的“长度”指的是离散化之前区间的实际长度) 然后模拟一个队列,区间按排好的顺序依次进入,直到某个点被覆盖了M次.之后依次出队,直到所有点都被覆盖小于M次 修改和询 ...

  6. 【BZOJ4653】【NOI2016】区间 线段树

    题目大意 数轴上有\(n\)个闭区间\([l_1,r_1],[l_2,r_2],\ldots,[l_n,r_n]\),你要选出\(m\)个区间,使得存在一个\(x\),对于每个选出的区间\([l_i, ...

  7. L3-2 森森快递 (30 分)(贪心+线段树/分块)

    题目链接:https://pintia.cn/problem-sets/1108203702759940096/problems/1108204121661857798 题目大意: 森森开了一家快递公 ...

  8. BZOJ.4653.[NOI2016]区间(线段树)

    BZOJ4653 UOJ222 考虑二分.那么我们可以按区间长度从小到大枚举每个区间,对每个区间可以得到一个可用区间长度范围. 我们要求是否存在一个点被这些区间覆盖至少\(m\)次.这可以用线段树区间 ...

  9. 2018.09.30 bzoj4025: 二分图(线段树分治+并查集)

    传送门 线段树分治好题. 这道题实际上有很多不同的做法: cdq分治. lct. - 而我学习了dzyo的线段树分治+并查集写法. 所谓线段树分治就是先把操作分成lognlognlogn个连续不相交的 ...

随机推荐

  1. centos6.6安装php5.3.3(2015/3/4)

    问题:centos6.6因要升级mysql5.5所以yum重新更新了源,导致按照原来lamp环境安装步骤,安装php时一直找webtitic源,php5.3.24 而且一直无法安装下去 利用yum r ...

  2. Java语言与C语言混合编程(2)--在Java中调用C语言本地库

    在上一篇文章中介绍了Java语言中的native关键字,以及Java语言调用C语言的编译生成本地动态链接库(DLL)实现加法运算的小例子,本文通过一个更加详细的例子,深入讲解Java语言调用C语言的函 ...

  3. jquery 操作单选按钮

    <input type="radio" name="sex" value="男" />男 <input type=&quo ...

  4. 【学习记录】二分查找的C++实现,代码逐步优化

    二分查找的思想很简单,它是针对于有序数组的,相当于数组(设为int a[N])排成一颗二叉平衡树(左子节点<=父节点<=右子节点),然后从根节点(对应数组下标a[N/2])开始判断,若值& ...

  5. 确保nginx安全的10个技巧

    Nginx是当今最流行的Web服务器之一.它为世界上7%的web流量提供服务而且正在以惊人的速度增长.它是个让人惊奇的服务器,我愿意部署它. 下面是一个常见安全陷阱和解决方案的列表,它可以辅助来确保你 ...

  6. charles 设置弱网测试

    Charles简介:Charles支持抓去http.https协议的请求,不支持socket. 然后charles会自动配置IE浏览器和工具的代理设置,所以说打开工具直接就已经是抓包状态了. 这里打开 ...

  7. TCP之二:TCP的三次握手与四次分手

    一.TCP是什么? 具体的关于TCP是什么,我不打算详细的说了:当你看到这篇文章时,我想你也知道TCP的概念了,想要更深入的了解TCP的工作,我们就继续.它只是一个超级麻烦的协议,而它又是互联网的基础 ...

  8. python解析时间格式脚本

    对于这种时间格式:發表於: 星期一 五月 28, 2012 6:59 am import re INPUT = "發表於: 星期一 五月 28, 2012 6:59 am 文章主題: 對&l ...

  9. canvas之太阳系效果

    星球 变量名 公转周期 光色 暗色 水星 Mercury 87.70 #a69697 #5c3e40 金星 Venus 224.701.70 #c4bbac #1f1315 地球 Earth 365. ...

  10. 【BZOJ】2818: Gcd(欧拉函数+质数)

    题目 传送门:QWQ 分析 仪仗队 呃,看到题后感觉很像上面的仪仗队. 仪仗队求的是$ gcd(a,b)=1 $ 本题求的是$ gcd(a,b)=m $ 其中m是质数 把 $ gcd(a,b)=1 $ ...