snoi模拟赛day4t1 查询

Description】

       给定一个含有N个非负整数的序列,请写一个程序,支持以下两个操作:

       1、Q l r   表示求l至r这一段所有数的和,结果对329701061取模

       2、C l r   表示将l至r这一段中的每一个数变为其立方。

  

       考场上想着打表找找取模之后的数有没有什么规律,忽然发现3次方一定次后会重复,接着发现每个数字3次方48次之后取模下来是一样的。

       所以我们可以建一棵线段树,里面存一个结构体,分别维护当前为[0~47]次立方的和。

       那么对于修改操作,

      首先考虑区间的更新:如果包含了一个完整的区间,我们可以直接将当前的区间整体右移1位,即(x+1)%48,当然还要给lazy标记+1。

      接着这样做了之后,覆盖它的区间[0~47]次立方的和,就可以直接加上当前区间的[0~47]次方,即永远默认当前区间的第一个位置为当前的值。

      对于向下传递函数,即需要给左儿子与右儿子加上当前的lazy值,然后将左儿子与右儿子的区间右移当前的lazy值位。

     最后查询的之后,只需要查询覆盖询问l,r的0次立方的和即可。

     下附AC代码。

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define maxn 100005
#define lson (now<<1)
#define rson ((now<<1)|1)
#define mid ((nl+nr)>>1)
using namespace std;
typedef long long ll;
const ll mod=329701061;
struct nod
{
	ll val[50];
	nod(){memset(val,0,sizeof(val));}
}dat[maxn<<2];
int n;
char s[20];
ll temp[50];
ll a[maxn],lazy[maxn<<2];
nod bing(nod a,nod b)
{
	nod ans;
	for(int i=0;i<48;i++) ans.val[i]=(a.val[i]+b.val[i])%mod;
	return ans;
}
void add(int now,int ad)
{
	for(int i=0;i<48;i++) temp[i]=dat[now].val[i];
	for(int i=0;i<48;i++) dat[now].val[i]=temp[(i+ad)%48];
}
void pushdown(int now)
{
	if(lazy[now])
	{
		add(lson,lazy[now]);
		add(rson,lazy[now]);
		lazy[rson]+=lazy[now];lazy[rson]%=48;
		lazy[lson]+=lazy[now];lazy[lson]%=48;
		lazy[now]=0;
	}
}
void pushup(int now)
{
	dat[now]=bing(dat[lson],dat[rson]);
}
void build(int now,int nl,int nr)
{
	if(nl==nr)
	{
		dat[now].val[0]=a[nl];
		for(int i=1;i<48;i++)
			dat[now].val[i]=(((dat[now].val[i-1]*dat[now].val[i-1])%mod)*dat[now].val[i-1])%mod;
		return;
	}
	build(lson,nl,mid);
	build(rson,mid+1,nr);
	pushup(now);
}
void add(int ql,int qr,int now,int nl,int nr)
{
	if(ql<=nl && nr<=qr)
	{
		lazy[now]++;lazy[now]%=48;
		add(now,1);
		return;
	}
	pushdown(now);
	if(ql<=mid) add(ql,qr,lson,nl,mid);
	if(mid<qr) add(ql,qr,rson,mid+1,nr);
	pushup(now);
}
int query(int ql,int qr,int now,int nl,int nr)
{
	if(ql<=nl && nr<=qr)
	return dat[now].val[0];
	pushdown(now);
	int ans=0;
	if(ql<=mid) ans+=query(ql,qr,lson,nl,mid),ans%=mod;
	if(mid<qr) ans+=query(ql,qr,rson,mid+1,nr),ans%=mod;
	pushup(now);
	return ans;
}
int main()
{
	freopen("query.in","r",stdin);
	freopen("query.out","w",stdout);
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	scanf("%lld",&a[i]);
	build(1,1,n);
	int _;
	scanf("%d",&_);
	while(_--)
	{
		int ql,qr;
		scanf("%s%d%d",s,&ql,&qr);
		if(s[0]=='C') add(ql,qr,1,1,n);
		else printf("%d\n",query(ql,qr,1,1,n));
	}
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值