SPOJ 11840. Sum of Squares with Segment Tree (线段树,区间更新)
http://www.spoj.com/problems/SEGSQRSS/
SPOJ Problem Set (classical)11840. Sum of Squares with Segment TreeProblem code: SEGSQRSS |
Segment trees are extremely useful. In particular "Lazy Propagation" (i.e. see
here, for example) allows one to compute sums over a range in O(lg(n)), and update ranges in O(lg(n)) as well. In this problem you will compute something much harder:
The sum of squares over a range with range updates of 2 types:
1) increment in a range
2) set all numbers the same in a range.
Input
There will be T (T <= 25) test
cases in the input file. First line of the input contains two positive integers, N (N <= 100,000) and Q
(Q <= 100,000). The next line contains N integers,
each at most 1000. Each of the next Qlines
starts with a number, which indicates the type of operation:
2 st nd -- return the sum of the squares of the numbers with
indices in [st, nd]
{i.e., from st to nd inclusive} (1
<= st <= nd <= N).
1 st nd x -- add "x" to all numbers with indices in [st, nd] (1
<= st <= nd <= N, and
-1,000 <= x <= 1,000).
0 st nd x -- set all numbers with indices in
[st, nd] to
"x" (1 <= st <= nd <= N, and
-1,000 <= x <= 1,000).
Output
For each test case output the “Case <caseno>:” in
the first line and from the second line output the sum of squares for each operation of type 2. Intermediate overflow will not occur
with proper use of 64-bit signed integer.
Example
Input:
2
4 5
1 2 3 4
2 1 4
0 3 4 1
2 1 4
1 3 4 1
2 1 4
1 1
1
2 1 1
Output:
Case 1:
30
7
13
Case 2:
1
Added by: | Chen Xiaohong |
Date: | 2012-07-11 |
Time limit: | 6s |
Source limit: | 50000B |
Memory limit: | 256MB |
Cluster: | Pyramid (Intel Pentium III 733 MHz) |
Languages: | All |
题意:
有三种操作:将区间中的全部数置为x;将区间中的全部数加上x;求区间内全部数的平方和。
分析:
先考虑假设不须要求平方和,仅仅是求和,我们须要维护这些数据:addv-区间内的数共同加上的值;setv-区间内的数都置为的值(setv=INF表示不设置);sumv-区间内的数加上addv之前的值。
但这题求的是平方和。似乎不是非常好维护。假设仅仅是set操作,还是非常好维护的,那么难点就在于add操作了。考虑例如以下等式:(x+v)^2=x^2+2xv+v^2,x是add操作之前的数,v是add的数。这是一个数的情况。那么一段区间内的数呢?
显然有sum(xi^2)+(v^2)*length+2*sum(xi)*v。这样问题就迎刃而解了,仅仅要再维护一个区间的平方和即可,当set时直接改,add时加上(v^2)*length+2*sum(xi)*v即可。
/*
*
* Author : fcbruce
*
* Time : Fri 03 Oct 2014 04:16:10 PM CST
*
*/
#include <cstdio>
#include <iostream>
#include <sstream>
#include <cstdlib>
#include <algorithm>
#include <ctime>
#include <cctype>
#include <cmath>
#include <string>
#include <cstring>
#include <stack>
#include <queue>
#include <list>
#include <vector>
#include <map>
#include <set>
#define sqr(x) ((x)*(x))
#define LL long long
#define itn int
#define INF 0x3f3f3f3f
#define PI 3.1415926535897932384626
#define eps 1e-10 #ifdef _WIN32
#define lld "%I64d"
#else
#define lld "%lld"
#endif #define maxm
#define maxn 100007 using namespace std; int addv[maxn<<2],setv[maxn<<2];
long long sumv[maxn<<2],sqrsumv[maxn<<2]; inline void pushdown(int k,int l,int r)
{
int lc=k*2+1,rc=k*2+2,m=l+r>>1;
addv[lc]+=addv[k];
addv[rc]+=addv[k];
addv[k]=0; if (setv[k]!=INF)
{
setv[lc]=setv[rc]=setv[k];
sumv[lc]=(LL)setv[lc]*(m-l);sumv[rc]=(LL)setv[rc]*(r-m);
sqrsumv[lc]=sqr((LL)setv[k]*(m-l));sqrsumv[rc]=sqr((LL)setv[rc])*(r-m);
addv[lc]=addv[rc]=0;
setv[k]=INF;
}
} inline void pushup(int k,int l,int r)
{
int lc=k*2+1,rc=k*2+2,m=l+r>>1; sumv[k]=sumv[lc]+sumv[rc]+(LL)addv[lc]*(m-l)+(LL)addv[rc]*(r-m);
sqrsumv[k]=sqrsumv[lc]+sqrsumv[rc]+(LL)(r-l)*(addv[k])+2ll*sumv[k]*addv[k];
} void build(int k,int l,int r)
{
addv[k]=0;
setv[k]=INF;
sumv[k]=sqrsumv[k]=0ll; if (r-l==1)
{
scanf("%d",&sumv[k]);
sqrsumv[k]=sqr((LL)sumv[k]);
return ;
} build(k*2+1,l,l+r>>1);
build(k*2+2,l+r>>1,r); pushup(k,l,r);
} void update_add(int a,int b,int v,int k,int l,int r)
{
if (b<=l || r<=a) return ;
if (a<=l && r<=b)
{
addv[k]+=v;
sqrsumv[k]+=sqr((LL)v)*(r-l)+2ll*v*sumv[k];
return ;
} pushdown(k,l,r); update_add(a,b,v,k*2+1,l,l+r>>1);
update_add(a,b,v,k*2+2,l+r>>1,r); pushup(k,l,r);
} void update_set(int a,int b,int v,int k,int l,int r)
{
if (b<=l || r<=a) return ;
if (a<=l && r<=b)
{
addv[k]=0;
setv[k]=v;
sumv[k]=(LL)v*(r-l);
sqrsumv[k]=sqr((LL)v)*(r-l);
return ;
} pushdown(k,l,r); update_set(a,b,v,k*2+1,l,l+r>>1);
update_set(a,b,v,k*2+2,l+r>>1,r); pushup(k,l,r);
} long long query(int a,int b,int k,int l,int r)
{
if (b<=l || r<=a) return 0ll;
if (a<=l && r<=b) return sqrsumv[k]; pushdown(k,l,r); return query(a,b,k*2+1,l,l+r>>1)+query(a,b,k*2+2,l+r>>1,r);
} int main()
{
#ifdef FCBRUCE
freopen("/home/fcbruce/code/t","r",stdin);
#endif // FCBRUCE int T_T,__=0;
scanf("%d",&T_T); while (T_T--)
{
int n,m;
scanf("%d%d",&n,&m); build(0,0,n); printf("Case %d:\n",++__); int op,a,b,v;
while (m--)
{
scanf("%d",&op); switch (op)
{
case 0:
scanf("%d%d%d",&a,&b,&v);
a--;
update_set(a,b,v,0,0,n);
break;
case 1:
scanf("%d%d%d",&a,&b,&v);
a--;
update_add(a,b,v,0,0,n);
break;
case 2:
scanf("%d %d",&a,&b);
a--;
printf(lld "\n",query(a,b,0,0,n));
break;
}
}
} return 0;
}
SPOJ 11840. Sum of Squares with Segment Tree (线段树,区间更新)的更多相关文章
- SPOJ GSS3-Can you answer these queries III-分治+线段树区间合并
Can you answer these queries III SPOJ - GSS3 这道题和洛谷的小白逛公园一样的题目. 传送门: 洛谷 P4513 小白逛公园-区间最大子段和-分治+线段树区间 ...
- SPOJ D-query &;&; HDU 3333 Turing Tree (线段树 &;&; 区间不相同数个数or和 &;&; 离线处理)
题意 : 给出一段n个数的序列,接下来给出m个询问,询问的内容SPOJ是(L, R)这个区间内不同的数的个数,HDU是不同数的和 分析 : 一个经典的问题,思路是将所有问询区间存起来,然后按右端点排序 ...
- BNU 28887——A Simple Tree Problem——————【将多子树转化成线段树+区间更新】
A Simple Tree Problem Time Limit: 3000ms Memory Limit: 65536KB This problem will be judged on ZJU. O ...
- HDU 4107 Gangster Segment Tree线段树
这道题也有点新意,就是须要记录最小值段和最大值段,然后成段更新这个段,而不用没点去更新,达到提快速度的目的. 本题过的人非常少,由于大部分都超时了,我严格依照线段树的方法去写.一開始竟然也超时. 然后 ...
- Implementation:Segment Tree 线段树
早就听人提起过线段树,今天有题搞不出来,讨论上说要用一下线段树,看了下,本质上是空间划分索引,只不过是一维上面的,如果在二维则是四叉树,三维则是八叉树,如果可以动态调整那么跟R-Tree就很相似了,他 ...
- SPOJ GSS1_Can you answer these queries I(线段树区间合并)
SPOJ GSS1_Can you answer these queries I(线段树区间合并) 标签(空格分隔): 线段树区间合并 题目链接 GSS1 - Can you answer these ...
- POJ.3321 Apple Tree ( DFS序 线段树 单点更新 区间求和)
POJ.3321 Apple Tree ( DFS序 线段树 单点更新 区间求和) 题意分析 卡卡屋前有一株苹果树,每年秋天,树上长了许多苹果.卡卡很喜欢苹果.树上有N个节点,卡卡给他们编号1到N,根 ...
- 【BZOJ3638】Cf172 k-Maximum Subsequence Sum 线段树区间合并(模拟费用流)
[BZOJ3638]Cf172 k-Maximum Subsequence Sum Description 给一列数,要求支持操作: 1.修改某个数的值 2.读入l,r,k,询问在[l,r]内选不相交 ...
- 【bzoj3638】Cf172 k-Maximum Subsequence Sum 模拟费用流+线段树区间合并
题目描述 给一列数,要求支持操作: 1.修改某个数的值 2.读入l,r,k,询问在[l,r]内选不相交的不超过k个子段,最大的和是多少. 输入 The first line contains inte ...
随机推荐
- 安卓 JDK、SDK、ADT 区别
问题一:android软件开发是用java语法,但是为什么开发环境还需要jdk,有android sdk不就可以了吗? 答: 我知道写字要用笔,但为什么还需要笔芯(墨水),有笔杆不就可以了吗? 问题二 ...
- js020-JSON
js020-JSON 20.1 语法 JSON的语法可以表示为一下三种类型的值. 简单值 使用与JS相同的语法,可以在JSON中表示字符串.数值.布尔值和null,但是JSON不支持JS中的特殊性Un ...
- strtok和strtok_r
1.strtok()函数的用法 函数原型:char *strtok(char *s, const char *delim); Function:分解字符串为一组字符串.s为要分解的字符串,delim为 ...
- 高级私人定制西服品牌:XUAN PRIVE 为定制而生_乐活_onlylady女人志
高级私人定制西服品牌:XUAN PRIVE 为定制而生_乐活_onlylady女人志 高级私人定制西服品牌:XUAN PRIVE 为定制而生
- LinkedList的分析(转)
一.源码解析 1. LinkedList类定义. public class LinkedList<E> extends AbstractSequentialList<E> im ...
- 把Excel工作簿的每个工作表提取出来保存为新工作簿
平台:MS office 2010 任务:有个excel工作簿,其中有上百个工作表,要求把每一个工作表全部保存为新工作簿,如果一个一个复制出来太傻了,可以用excel自带的VB解决. 方法:打开工作簿 ...
- 第二章:在HTML中使用JavaScript
1:在使用<script>嵌入JavaScript代码死,记住不要在代码中的任何地方出现"</script>"字符串 例如,浏览器在加载下面所示代码时就会产 ...
- Django中下划线的用法介绍(一)
在Django中有相当多的操作是通过双下划线与动作连接起来使用,为了以后更加方便的查找和使用,现在总结以下Django中基本的双下划线操作 比较符:大于--gt 小于--lt 等于--eq 大于等 ...
- JAVA_SE基础——62.String类的构造方法
下面我先列出初学者目前用到的构造方法 String 的构造方法: String() 创建一个空内容 的字符串对象. String(byte[] bytes) 使用一个字节数组构建一个字 ...
- day14.生成器进阶,推导式
生成器中取值的三种方法 方法1:next() 方法2:for 循环 方法3:数据类型的强制转换 def func(): for i in range(20): yield '赛车*{}'.format ...