hdu 4267 A Simple Problem with Integers 线段树,区间部分更新
http://acm.hdu.edu.cn/showproblem.php?pid=4267
题意:
给你N个数,有两种操作:
2 x询问a[x]的值;
1 a b k c a <= i <= b 满足(i - a)%k == 0的a[i] += c;
(1 <= N <= 50000) (1 <= a <= b <= N, 1 <= k <= 10, -1,000 <= c <= 1,000)
思路:
一看就知道这肯定是线段树的题目,可是区间内满足(i - a)%k == 0的点才进行处理怎么办,如果i i + k,i + 2k的循环处理的话,就都变成的了单点更新了,时间复杂度O(n^2)就不行可。
这里肯定要优化到O(nlogn),才开始想记录1操作,区间[a,b]按平常加,每次询问点时再枚举所有的1减去多加了,发现只能优化到O(n^2/2)写了一下TLE.后来看了解题报告才恍然大悟。
线段树上的每个点表示一个区间,我们记录该区间所有模i于j的点的值,由于1 <= k <= 10 所以总共有55中可能,把每个区间的所有可能记录,然后区间更新时,只要将该区间所有满足的情况累加一边就好了,单点询问的话只需要将所有情况累加即可。
i%k = a%k;
View Code
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <queue> #include <stack> #include <set> #include <map> #include <string> #define CL(a,num) memset((a),(num),sizeof(a)) #define iabs(x) ((x) > 0 ? (x) : -(x)) #define Min(a,b) (a) > (b)? (b):(a) #define Max(a,b) (a) > (b)? (a):(b) #define ll __int64 #define inf 0x7f7f7f7f #define lc l,m,rt<<1 #define rc m + 1,r,rt<<1|1 #define pi acos(-1.0) #define test puts("<------------------->") #define maxn 100007 #define M 100007 #define N 50007 using namespace std; //freopen("din.txt","r",stdin); struct node{ int l,r; int mod[55];//记录模k的各种情况 int lz; int mid(){ return (l + r)>>1; } }a[4*N]; int mk[11][11],b[N]; void init(){ int i,j; int ct = 0; for (i = 1; i <= 10; ++i){ for (j = 0; j < i; ++j) mk[i][j] = ct++;//将其转变为1维 } } void pushdown(int rt){ if (a[rt].lz){ a[rt<<1].lz += a[rt].lz; a[rt<<1|1].lz += a[rt].lz; a[rt].lz = 0; for (int i = 0; i < 55; ++i){ a[rt<<1].mod[i] += a[rt].mod[i]; a[rt<<1|1].mod[i] += a[rt].mod[i]; a[rt].mod[i] = 0; } } } void build(int l,int r,int rt){ a[rt].l = l; a[rt].r = r; a[rt].lz = 0; CL(a[rt].mod,0); if (l == r) return; int m = a[rt].mid(); build(lc); build(rc); } void update(int L,int R,int k,int MOD,int sc,int rt){ if (a[rt].l >= L && a[rt].r <= R){ a[rt].lz += sc; a[rt].mod[mk[k][MOD]] += sc;//模k等于MOD的累加 return; } pushdown(rt); int m = a[rt].mid(); if (L <= m) update(L,R,k,MOD,sc,rt<<1); if (R > m) update(L,R,k,MOD,sc,rt<<1|1); } int query(int pos,int rt){ if (a[rt].l == a[rt].r){ int tmp = 0; for (int i = 1; i <= 10; ++i){ tmp += a[rt].mod[mk[i][pos%i]];//枚举当前点模1-10的所有可能 } return b[a[rt].l] + tmp; } pushdown(rt); int res = 0; int m = a[rt].mid(); if (pos <= m) res = query(pos,rt<<1); else res = query(pos,rt<<1|1); return res; } int main(){ //freopen("din.txt","r",stdin); int i,n,m; int op,x,y,c,k; init(); while (~scanf("%d",&n)){ for (i = 1; i <= n; ++i) scanf("%d",&b[i]); build(1,n,1); scanf("%d",&m); while (m--){ scanf("%d",&op); if (op == 2){ scanf("%d",&x); printf("%d\n",query(x,1)); } else{ scanf("%d%d%d%d",&x,&y,&k,&c); update(x,y,k,x%k,c,1); } } } return 0; }