问题 D: Segment Balls
时间限制: 1 Sec 内存限制: 128 MB 提交: 253 解决: 37题目描述
Small K has recently earn money in stock market , so he want to make balls to celebrate it.
Now he buys so many balls , and he want to put it into the boxes , he will have two operators to do it.
There are n boxes , which number is in range of (1 , n)
operator 1: PUT B C he can put C balls to boxes whose number is multiple of B
operator 2: QUERY D E he want to know the total number of balls in boxes number D to boxes number E.
We guarantee that 1 <= B ,C <= 10 1 <= D <= E <= 1e6
输入
The first number CASE is the case number.Then will be CASE cases.
At every case , the first number is n(1<=n<=10^6) ,means that we have n boxes.
the second number is q , which means the q operators will be give.
And then will be q lines ,which means q operators.
(1 <= q <= 100000)
输出
Every case , print the total balls for every question . A question a line.
样例输入
1 4 8 PUT 1 3 QUERY 2 4 PUT 2 3 QUERY 1 4 QEURY 1 1 QEURY 2 2 QUERY 3 3 QUERY 4 4
样例输出
9 18 3 6 3 6
题意:有n个空盒子,进行两种操作:
1)PUT x y 给标号为x的倍数的盒子全加上y个球。
2)QUERY x y 求标号从x到y的盒子里总球数。
分析:维护每次给线段加的倍数x及加数y,那么给每段加上y*(该段上x的倍数点总数(r-l)/x)即可维护每段的总和,x最多有
10种,因此刚开始直接来用第二维为10的lazy数组标志,但爆内存了,后来改用vector,代码各种乱,还好最后几分钟AC了。
这题有更简便的方法,直接开个大小为11的数组记录好整段每种的倍数的put值,最后加上所有的put值乘以线段长度/倍数x即可。

#include <cstdio> #include <cstring> #include <string> #include <cmath> #include <iostream> #include <algorithm> #include <queue> #include <cstdlib> #include <stack> #include <vector> #include <set> #include <map> #define LL long long #define mod 100000000 #define inf 0x3f3f3f3f #define eps 1e-6 #define N 1000010 #define FILL(a,b) (memset(a,b,sizeof(a))) #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 using namespace std; int n; struct node { int x,y; }; LL sum[N<<2]; vector<node>col[N<<2]; void Pushup(int rt) { int ls=rt<<1,rs=ls|1; sum[rt]=sum[ls]+sum[rs]; } void build(int l,int r,int rt) { if(l==r) { sum[rt]=0; return; } int m=(l+r)>>1; build(lson); build(rson); Pushup(rt); } int cal(int i,int l,int r)//计算该段倍数为i的点总数 { int len=0,num=1; for(int j=l;j<=r&&num<=10;j++) { num++; if(j%i==0) { l=j;len++; break; } } len+=(r-l)/i; return len; } void Pushdown(int rt,int l,int r) { int ls=rt<<1,rs=ls|1; int m=(l+r)>>1; for(int i=0,sz=col[rt].size();i<sz;i++) if(col[rt][i].y) { int flag=0; for(int j=0,z=col[ls].size();j<z;j++)//维护10种x值即可 { if(col[ls][j].x==col[rt][i].x) { col[ls][j].y+=col[rt][i].y;flag=1;break; } } if(!flag)col[ls].push_back(col[rt][i]); flag=0; for(int j=0,z=col[rs].size();j<z;j++) { if(col[rs][j].x==col[rt][i].x) { col[rs][j].y+=col[rt][i].y;flag=1;break; } } if(!flag)col[rs].push_back(col[rt][i]); sum[ls]+=1LL*col[rt][i].y*cal(col[rt][i].x,l,m);//同样维护好sum值 sum[rs]+=1LL*col[rt][i].y*cal(col[rt][i].x,m+1,r); } col[rt].clear(); } void update(int L,int R,int x,int y,int l,int r,int rt) { if(L<=l&&r<=R) { int flag=0; for(int i=0,sz=col[rt].size();i<sz;i++)//维护10种x值即可 { if(col[rt][i].x==x) { col[rt][i].y+=y;flag=1;break; } } node now; now.x=x;now.y=y; if(!flag)col[rt].push_back(now); sum[rt]+=1LL*y*cal(x,l,r);//加上y*(x的倍数点和) return; } } LL query(int L,int R,int l,int r,int rt)//求区间和 { if(L<=l&&r<=R)return sum[rt]; Pushdown(rt,l,r); int m=(l+r)>>1; LL res=0; if(L<=m)res+=query(L,R,lson); if(m<R)res+=query(L,R,rson); return res; } int main() { int T,q; scanf("%d",&T); while(T--) { scanf("%d%d",&n,&q); for(int i=0;i<=n;i++)col[i].clear(); build(1,n,1); while(q--) { char op[10]; int x,y; scanf("%s%d%d",op,&x,&y); if(op[0]=='P') { update(1,n,x,y,1,n,1); } else { if(x>n) { puts("0");continue; } if(y>n)y=n; printf("%lld ",query(x,y,1,n,1)); } } } }