hdu4267 A Simple Problem with Integers(多棵线段树)
来源:互联网 发布:平面构成 知乎 编辑:程序博客网 时间:2024/06/05 05:52
A Simple Problem with Integers
Time Limit: 5000/1500 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 2520 Accepted Submission(s): 814
The first line contains an integer N. (1 <= N <= 50000)
The second line contains N numbers which are the initial values of A1, A2, ... , AN. (-10,000,000 <= the initial value of Ai <= 10,000,000)
The third line contains an integer Q. (1 <= Q <= 50000)
Each of the following Q lines represents an operation.
"1 a b k c" means adding c to each of Ai which satisfies a <= i <= b and (i - a) % k == 0. (1 <= a <= b <= N, 1 <= k <= 10, -1,000 <= c <= 1,000)
"2 a" means querying the value of Aa. (1 <= a <= N)
4 1 1 1 1142 12 22 32 41 2 3 1 22 1 2 22 32 41 1 4 2 12 12 22 32 4
111113312341
题目大意:经典线段树模型。2种操作,单点查询,更新的时候是更新一群离散的点。
题目分析:好像就剩这种线段树没写过了,比赛的时候还真遇上了。。。于是开始苦逼的yy,好歹还是被yy出来了。30分钟搞定。只可惜一开始没信心,没敢写。。。好像有更高级的做法,不过作为菜鸟,还是苦逼的写了55棵线段树。。。
这题给了5w个点,但是更新的时候是更新一段区间内等距离的一些离散的点,单点更新肯定要TLE,所以必须另辟蹊径。更新的点是这样的,对于每个更新操作,给一个更新区间,[a,b],每次只更新[a,b]中(i - a)%k == 0的点,k给定的。k<=10。
整理一下发现,所要更新的点i = a + n*k,即i%k = a%k,而k<=10,于是对于每个k,每次更新的点就有k种情况,没错,就是k种情况,对于每个k,因为k有0~k-1,k个余数,k<=10的话,一共就有55种情况。所以维护55棵线段树。所以每次按余数来,对于每个更新操作,只要一次成段更新就ok了,查询的时候找到每个k对应的树,统计求和即可。
具体线段树的分布:
下标从0-54
当k= 1的时候,只有模k=0,所以第0棵线段树存模1的操作,其实就是起始的线段树;
当k=2的时候,有i%k=0和i%k = 1两种情况,所以对于所有%2=0的点,更新到第1棵线段树上,对所有%2=1的点,更新到第2棵线段树上;
当。。。。
以此类推,一共55棵线段树。
可能有点抽象,举个稍微具体的例子:
例如给一个更新操作a=5,b=13,k = 3,那么实际上我们需要更新的点只有5,8,11,这3个数都有一个共同的特点就是模3为2,那么模3为2对应第5棵线段树,那么我们只需要在第5棵线段树上成段更新区间5~13即可,只要更新5,8,11三个点,为什么我们要更新一个区间呢,因为这根本不影响我们查询结果,比如我们要统计第5个点的值,那么我们只要依次统计5%1,5%2,5%3....5%10这10棵线段树上的第5个点上值的和就可以了,其中第5棵线段树上的第5个点的值就是5%3的时候更新的结果,所以虽然我们在第5棵线段树上更新了一个区间,但实际上查询的时候只有模3余2的点才能查询到这棵线段树,所以刚才的成段更新是没问题的。比如要查询第9个点的值,虽然我们在第5棵线段树上更新了第9个点,但实际查询的时候,9%3==0,只能查询到第3棵线段树,第5棵线段树对第9个点的值是没有影响的。
详情请见代码:
#include <iostream>#include<cstdio>#include<cstring>#include<cstdlib>#include<cmath>#include<algorithm>#include<map>#include<set>#include<vector>#include<queue>using namespace std;const int N = 50001;const double eps = 1e-6;const double PI = acos(-1.0);int n,m;int kid[] = {0,0,1,3,6,10,15,21,28,36,45};struct node{ int lcm[N + N + N]; void build(int num,int s,int e) { lcm[num] = 0; if(s == e) return; int mid = (s + e)>>1; build(num<<1,s,mid); build(num<<1|1,mid + 1,e); } void insert(int num,int s,int e,int l,int r,int val) { if(s == l && r == e)//成段更新,省去了lazy标记 { lcm[num] += val; return; } if(lcm[num])//下传 { lcm[num<<1] += lcm[num]; lcm[num<<1|1] += lcm[num]; lcm[num] = 0; } int mid = (s + e)>>1; if(r <= mid) insert(num<<1,s,mid,l,r,val); else { if(l > mid) insert(num<<1|1,mid + 1,e,l,r,val); else { insert(num<<1,s,mid,l,mid,val); insert(num<<1|1,mid + 1,e,mid + 1,r,val); } } } int query(int num,int s,int e,int pos) { if(s == e) return lcm[num]; if(lcm[num])//下传 { lcm[num<<1] += lcm[num]; lcm[num<<1|1] += lcm[num]; lcm[num] = 0; } int mid = (s + e)>>1; if(pos <= mid) return query(num<<1,s,mid,pos); else return query(num<<1|1,mid + 1,e,pos); }}tree[55];int main(){ int i; int t; int a,b,k,op,c; while(scanf("%d",&n) != EOF) { for(i = 0;i < 55;i ++) tree[i].build(1,1,n); for(i = 1;i <= n;i ++) { scanf("%d",&t); tree[0].insert(1,1,n,i,i,t); } scanf("%d",&m); while(m --) { scanf("%d",&op); if(op == 2) { int ans = 0; scanf("%d",&a); for(i = 1;i <= 10;i ++) { int id = kid[i] + a % i; ans += tree[id].query(1,1,n,a); } printf("%d\n",ans); } else { scanf("%d%d%d%d",&a,&b,&k,&c); int id = kid[k] + a % k; tree[id].insert(1,1,n,a,b,c); } } } return 0;}//312MS28728K
没想到这题代码这么段,写的也比较顺利,可是效率好像不高。。。
不过这题最好还是用树状数组写,速度快,写起来比较方便,更重要的是省空间。这题开55棵线段树很容易爆内存的。因为操作不是很复杂,只要维护一个前缀和就行了,所以树状数组解此题更适合。
- hdu4267 A Simple Problem with Integers(多棵线段树)
- hdu4267---A Simple Problem with Integers(线段树)
- hdu4267 A Simple Problem with Integers
- HDU4267 A Simple Problem with Integers
- hdu4267 A Simple Problem with Integers
- 线段树—区间更新 HDU4267 A Simple Problem With Integers
- A Simple Problem with Integers(线段树)
- A Simple Problem with Integers----线段树
- 线段树 A Simple Problem with Integers
- 线段树 A Simple Problem with Integers
- HDU4267 A Simple Problem with Integers(树状数组)
- hdu4267--A Simple Problem with Integers(树状数组)
- A Simple Problem with Integers(树状数组HDU4267)
- POJ 3468 A Simple Problem with Integers(线段树)
- [PKU] 3468 A Simple Problem with Integers -- 线段树
- POJ 3468 A Simple Problem with Integers (线段树)
- pku -- 3468 A Simple Problem with Integers(线段树)
- POJ 3468 A SIMPLE PROBLEM WITH INTEGERS(线段树)
- 创建存储过程
- latex下标符号的上下堆积
- 1
- 反射机制
- VB6基本数据库应用(二):建立数据库
- hdu4267 A Simple Problem with Integers(多棵线段树)
- Server.MapPath()相关
- hdu1010
- vs2010 快捷键大全
- corejava[读书笔记]第四章
- usb---端点
- 利用txt编写网页(很基础的一部分)
- 学生管理系统问题集锦二
- 代码集