#2212 幼儿园 【线段树入门】

版权声明:----------------------------------------转载是ok的,但要附上出处哟 https://blog.csdn.net/qq_43040655/article/details/86843840

描述
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
幼儿园里的小朋友们正在和老师玩一个有趣的游戏。小朋友们被分成了 N 小组,初始时第i小组的人数为 ai 。老师先选定一些编号在[l,r]内的小组,然后开始与这段连续的小组的一次游戏。游戏是这样进行的:每次游戏分成若干轮,每一轮老师转过身去,[l,r]中的小组的小朋友们需要在这时通过选举选出 3 个来自不同小组的小朋友上前领老师的糖果, 并且为了体现公平,以下情形被视为犯规:某一轮选出了 3 个人领糖果,而后来这 3 个人又在同一 轮被选举出来领糖果。现在老师会不时地问你:假如他与编号在[l,r]内的小组做一次游戏,则最多能玩多少轮。小组不是固定的,人数会不时发生变化。

输入
第一行两个整数 N, M ,分别为小组数目和事件数目。

第二行 N 个整数表示 ai 。

接下来 M 行,每行描述一个事件。事件为以下两类之一(第一个数为事件类型) :

1 l r 表示询问

2 id p 表示第id 个小组的人数变成 p 。

输出
对于每一个询问操作,输出一行一个整数为答案。因为答案可能很大,只需要输出其对 1e9 + 7 取模后的结果即可。

样例输入 [复制]
5 3
1 2 3 4 5
1 1 3
2 1 2
1 1 3
样例输出 [复制]
6
12
提示
数据约束

对于 30%的数据, N, M <= 50 。

对于 50%的数据, N, M <= 5000 。

对于 100%的数据,1<= N, M<=100000,1<= ai, p <=10^9+ 7 。

提示

注意乘法溢出问题

///////////////////////////////////////////////////////////////////////////////////////////////

线段树水题啊。。
实在不懂 合并操作和维护值的类型的,评论区留言吧。。。。。
(不写快速乘可以水过去,而且快得多。。。)

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define lc (p<<1)
#define rc ((p<<1)|1)
const int maxn=1e5+10,mod=1e9+7;

inline int ksc(int a,int b){
	if(a<b)swap(a,b);
	int ans=0;
	while(b){
		if(b&1)ans=(ans+a)%mod;
		a=(a+a)%mod;
		b>>=1;
	}
	return ans;
}

struct T{
	int l,r;
	int s[3];
}t[maxn<<2];
int a[maxn];
inline T merge(T l,T r){
	T ans;
	ans.l=l.l,ans.r=r.r;
	ans.s[0]=l.s[0]+r.s[0];ans.s[0]%=mod;
	ans.s[1]=ksc(l.s[0],r.s[0])+l.s[1]+r.s[1]; ans.s[1]%=mod;
	ans.s[2]=ksc(l.s[1],r.s[0])+ksc(l.s[0],r.s[1])+l.s[2]+r.s[2];ans.s[2]%=mod;
	return ans;
}
inline void build(int p,int l,int r){
	t[p].l=l,t[p].r=r;
	if(l==r){
		t[p].s[0]=a[l];
		return;
	}
	int mid=(l+r)>>1;
	build(lc,l,mid);
	build(rc,mid+1,r);
	t[p]=merge(t[lc],t[rc]);
}
inline void change(int p,int k,int v){
	if(t[p].l==t[p].r){
		t[p].s[0]=v;
		return;
	}
	int mid=(t[p].l+t[p].r)>>1;
	if(k<=mid)  change(lc,k,v);
	else change(rc,k,v);
	//cerr<<0<<" "<<t[p].l<<" "<<t[p].r<<" "<<t[p].s[2]<<endl;
	t[p]=merge(t[lc],t[rc]);
	//cerr<<1<<" "<<t[p].l<<" "<<t[p].r<<" "<<t[p].s[2]<<endl;
}
inline T query(int p,int ql,int qr){
	if(t[p].l>=ql&&t[p].r<=qr){
		return t[p];
	}
	int mid=(t[p].l+t[p].r)>>1;
	if(qr<=mid) return query(lc,ql,qr);
	else if (ql>mid)  return query(rc,ql,qr);
	else return merge(query(lc,ql,qr),query(rc,ql,qr));
}

signed main(){
	int n,m;
	scanf("%lld%lld",&n,&m);
	for(int i=1;i<=n;++i)scanf("%lld",&a[i]);
	build(1,1,n);
	while(m--){
		int a,b,c;scanf("%lld%lld%lld",&a,&b,&c);
		if(a==1){
			printf("%lld\n",query(1,b,c).s[2]);
		}
		else{
			change(1,b,c);
		}
	}
	return 0;
	
} 

猜你喜欢

转载自blog.csdn.net/qq_43040655/article/details/86843840