卿学姐种花
Time Limit: 0/7500MS (Java/Others) Memory Limit: 0/220000KB (Java/Others)
众所周知,在喵哈哈村,有一个温柔善良的卿学姐。
卿学姐喜欢和她一样美丽的花。所以卿学姐家的后院有很多的花坛。
卿学姐有 n n个花坛,一开始第 i i个花坛里有 A[i] A[i]朵花。每过一段时间,卿学姐都会在花坛里种上新的花。
作为一个聪明的学姐,卿学姐的种花方式也是与众不同 , 每一次,卿学姐会在第 x x个花坛种上 y y朵花,然后在第 x+1 x+1个花坛上种上 y−1 y−1朵花,再在第 x+2 x+2个花坛上种上 y−2 y−2朵花......以此类推,直到种到最后一个花坛,或者不需要种花为止。
喵哈哈的村民们都喜欢去卿学姐的后院赏花,沈宝宝也不例外。然而沈宝宝可不是省油的灯,怎么可能会老老实实地赏花呢。每次沈宝宝来时,都会随机询问卿学姐在第 i i个花坛有多少朵花。
花坛的花实在太多了,卿学姐实在是数不过来。于是现在她向你求助,希望你能帮她数出花坛里多少朵花。
Input
第一行输入两个整数,花坛个数 N N和操作次数 Q Q。
第二行 N N个整数 A[1],A[2],A[3].....A[N] A[1],A[2],A[3].....A[N]。 ( 1≤A[i]≤231 1≤A[i]≤231 )
接下来 Q Q行,每行一个操作。
-
1 x y
表示卿学姐会在 x x号花坛种 y y朵花,并按相应的规律在后面的花坛上种花。 -
2 x
表示沈宝宝问卿学姐第 x x个花坛有多少朵花。
数据保证:
-
1≤N≤104 1≤N≤104
-
1≤Q≤2∗106 1≤Q≤2∗106
-
∑x≤108 ∑x≤108, x x代表操作 2 2 的询问下标
-
对于操作 1 1 , 1≤x≤N 1≤x≤N, 1≤y≤109 1≤y≤109
-
对于操作 2 2 , 1≤x≤N 1≤x≤N
Output
对于每个询问操作,按顺序输出答案对 772002+233 772002+233取模的值。
Sample input and output
Sample Input |
Sample Output
|
---|---|
6 3 1 2 3 2 1 2 1 2 3 2 3 2 6 | 5 2 |
Hint
第一次种花会在第 2 2号花坛种 3 3朵,第 3 3号花坛种 2 2朵,第 4 4号花坛种 1 1朵,由于在第 5 5号花坛不用种花,所以就不再继续种花了,最终每个花坛花的数量分别为 1,5,5,3,1 1,5,5,3,1。
思路:
一开始根本没想到使用线段树的,因为线段树都是要在相同的区间更新相同的值,所以感觉不像。但是想了好久暴力的方法都是预处理都会超时,最重要的是发现了一点,
那就是这个查询必须是在线的查询,所以可以肯定用线段树是可行的。之后就是要优化了。一开始想直接更新到叶子结点,结果TLE4,之后发现了原来多次输入都是可以累加
在一起的,所以就加多一个更新区间的次数就AC了。
TLE代码:
#include<iostream>
#include<functional>
#include<algorithm>
#include<cstring>
#include<string>
#include<vector>
#include<cstdio>
#include<queue>
#include<cmath>
#include<map>
#include<set>
using namespace std;
#define CRL(a) memset(a,0,sizeof(a))
#define QWQ ios::sync_with_stdio(0)
#define inf 0x3f3f3f3f
typedef unsigned long long LL;
typedef long long ll;
const int T = 10000+50;
const int mod = 1000000007;
const int mo = 772002+233;
#define lson (rt<<1)
#define rson (rt<<1|1)
ll n,m;
struct node
{
ll v,lazy,tar;
int L,R,mid;
}tree[T<<3];
void Push_Down(int rt)
{
if(tree[rt].lazy){
if(tree[rt].L==tree[rt].R&&tree[rt].lazy){
tree[rt].v += tree[rt].lazy - (tree[rt].L-tree[rt].tar);
}
else {
tree[rson].lazy = tree[lson].lazy = tree[rt].lazy;
tree[rson].tar = tree[lson].tar = tree[rt].tar;
}
tree[rt].lazy = 0;
tree[rt].tar = 0;
}
}
void Build(int rt,int L,int R)
{
tree[rt].L = L,tree[rt].R = R;
tree[rt].mid = (L+R)>>1;
tree[rt].tar = tree[rt].lazy = 0;
if(L==R){
scanf("%lld",&tree[rt].v);
return;
}
Build(lson,L,tree[rt].mid);
Build(rson,tree[rt].mid+1,R);
}
void Insert(int rt,int L,int R,ll val,int tar)
{
if(L<=tree[rt].L&&R>=tree[rt].R&&!tree[rt].lazy
||tree[rt].L==tree[rt].R){
Push_Down(rt);
tree[rt].lazy = val;
tree[rt].tar = tar;
return;
}
//Push_Down(rt);
if(R<=tree[rt].mid){
Insert(lson,L,R,val,tar);
}
else if(L>tree[rt].mid){
Insert(rson,L,R,val,tar);
}
else {
Insert(lson,L,tree[rt].mid,val,tar);
Insert(rson,tree[rt].mid+1,R,val,tar);
}
}
ll query(int rt,int pos)
{
if(tree[rt].L==pos&&tree[rt].R==pos){
if(tree[rt].lazy)
return tree[rt].v + tree[rt].lazy - (pos-tree[rt].tar);
return tree[rt].v;
}
if(pos<=tree[rt].mid){
if(tree[rt].lazy)
return query(lson,pos) + tree[rt].lazy - (pos-tree[rt].tar);
return query(lson,pos);
}
else{
if(tree[rt].lazy)
return query(rson,pos) + tree[rt].lazy - (pos-tree[rt].tar);
return query(rson,pos);
}
}
int main()
{
#ifdef zsc
freopen("input.txt","r",stdin);
#endif
int i,j,k;
while(~scanf("%lld%lld",&n,&m))
{
Build(1,1,n);
ll num,u,v;
for(i=0;i<m;++i){
scanf("%lld",&num);
if(num==1){
scanf("%lld%lld",&u,&v);
Insert(1,u,min(u+v-1,n),v,u);
}
else {
scanf("%lld",&u);
printf("%lld\n",query(1,u)%mo);
}
}
}
return 0;
}
TLE(在n=10^6TLE,10^4可以接受)代码:
这道算法题被改为n=10^6时,线段树被卡内存了,结果想到了分快做,结果又没考虑时间复杂度又太高了,醉了。
#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<cstdio>
#include<cmath>
#include<queue>
#include<vector>
#include<set>
using namespace std;
const int T=1000000+50;
const int N=2000;
#define inf 0x3f3f3f3fL
#define mod 1000000000
typedef long long ll;
typedef unsigned long long ULL;
int sz;
ll num[T],Delta[N];
int main()
{
#ifdef zsc
freopen("input.txt","r",stdin);
#endif
int n,m,i,j,k;
while(~scanf("%d%d",&n,&m))
{
sz = sqrt(n);
for(i=0;i<n;++i){
scanf("%lld",&num[i]);
}
int OP,x,y,tar,L,R;
while(m--)
{
scanf("%d",&OP);
if(OP==1){
scanf("%d%d",&x,&y);
ll tmp = y;
L = x,R = min(x+y,n);
L--,R--;
int LB=L/sz,RB=R/sz;
for(i=min((LB+1)*sz-1,R);i>=L;--i){
num[i] += tmp--;
}
if(tmp<=0)continue;
for(i=LB+1;i<=RB-1;++i){
Delta[i] += tmp;
tmp -= sz;
if(tmp<=0)break;
}
if(LB==RB||tmp<=0)continue;
for(i=RB*sz;i<=R;++i){
num[i] += tmp--;
if(tmp<=0)break;
}
}
else {
scanf("%d",&tar);tar--;
printf("%lld\n",num[tar]+Delta[tar/sz]);
}
}
}
return 0;
}
AC代码:
#include<iostream>
#include<functional>
#include<algorithm>
#include<cstring>
#include<string>
#include<vector>
#include<cstdio>
#include<queue>
#include<cmath>
#include<map>
#include<set>
using namespace std;
#define CRL(a) memset(a,0,sizeof(a))
#define QWQ ios::sync_with_stdio(0)
#define inf 0x3f3f3f3f
typedef unsigned long long LL;
typedef long long ll;
const int T = 10000+50;
const int mod = 1000000007;
const int mo = 772002+233;
#define lson (rt<<1)
#define rson (rt<<1|1)
ll n,m;
struct node
{
ll v,lazy,tar,cnt;
int L,R,mid;
}tree[T<<3];
void Push_Down(int rt)//向下更新左右孩子
{
if(tree[rt].lazy){
tree[rson].lazy += tree[rt].lazy;
tree[lson].lazy += tree[rt].lazy;
tree[rson].cnt += tree[rt].cnt;
tree[lson].cnt += tree[rt].cnt;
tree[rson].tar += tree[rt].tar;
tree[lson].tar += tree[rt].tar;
tree[rt].lazy = 0;
tree[rt].tar = 0;
tree[rt].cnt = 0;
}
}
void Build(int rt,int L,int R)//建立二叉树
{
tree[rt].L = L,tree[rt].R = R;
tree[rt].mid = (L+R)>>1;
tree[rt].cnt = 0;
tree[rt].tar = tree[rt].lazy = 0;
if(L==R){
scanf("%lld",&tree[rt].v);
return;
}
Build(lson,L,tree[rt].mid);
Build(rson,tree[rt].mid+1,R);
}
void Insert(int rt,int L,int R,ll val,int tar)
{
if(L<=tree[rt].L&&R>=tree[rt].R){//当符合区间
tree[rt].cnt++;
tree[rt].lazy += val;
tree[rt].tar += tar;
return;
}
Push_Down(rt);
if(R<=tree[rt].mid){
Insert(lson,L,R,val,tar);
}
else if(L>tree[rt].mid){
Insert(rson,L,R,val,tar);
}
else {
Insert(lson,L,tree[rt].mid,val,tar);
Insert(rson,tree[rt].mid+1,R,val,tar);
}
}
ll query(int rt,int pos)
{
if(tree[rt].L==pos&&tree[rt].R==pos){//到叶子节点
if(tree[rt].lazy)
return tree[rt].v + tree[rt].lazy - (tree[rt].cnt*pos-tree[rt].tar);
return tree[rt].v;
}
//之后一路回溯回去,如果路上存在数值就加上去
if(pos<=tree[rt].mid){
if(tree[rt].lazy)
return query(lson,pos) + tree[rt].lazy - (tree[rt].cnt*pos-tree[rt].tar);
return query(lson,pos);
}
else{
if(tree[rt].lazy)
return query(rson,pos) + tree[rt].lazy - (tree[rt].cnt*pos-tree[rt].tar);
return query(rson,pos);
}
}
int main()
{
#ifdef zsc
freopen("input.txt","r",stdin);
#endif
int i,j,k;
while(~scanf("%lld%lld",&n,&m))
{
Build(1,1,n);
ll num,u,v;
for(i=0;i<m;++i){
scanf("%lld",&num);
if(num==1){//插入字符u与种v花
scanf("%lld%lld",&u,&v);
Insert(1,u,min(u+v-1,n),v,u);
}
else {//查询u位置的花
scanf("%lld",&u);
printf("%lld\n",query(1,u)%mo);
}
}
}
return 0;
}