卿学姐种花(线段树)

                                                  卿学姐种花

                                                                                            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个花坛上种上 y1 y−1朵花,再在第 x+2 x+2个花坛上种上 y2 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]。 ( 1A[i]231 1≤A[i]≤231 )

接下来 Q Q行,每行一个操作。

  1. 1 x y 表示卿学姐会在 x x号花坛种 y y朵花,并按相应的规律在后面的花坛上种花。

  2. 2 x 表示沈宝宝问卿学姐第 x x个花坛有多少朵花。

数据保证:

  • 1N104 1≤N≤104

  • 1Q2106 1≤Q≤2∗106

  • x108 ∑x≤108 x x代表操作 2 2 的询问下标

  • 对于操作 1 1 , 1xN 1≤x≤N 1y109 1≤y≤109

  • 对于操作 2 2 , 1xN 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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值