ZOJ4009 And Another Data Structure Problem(线段树+循环节)

题目

数据范围如上,两种操作,一种区间立方和,一种区间求和对99971取模

思路来源

https://blog.csdn.net/qq_31759205/article/details/79520745

题解

思维新奇.jpg

打表,发现这玩意有循环节,我怎么可能知道

对任意数x,x*x*x%99971在48次时出现循环节

于是,线段树多开一维,同时维护当前这个区间如果是第0到47次被立方时的答案

类似标记永久化(?)/树上前缀和的东西,也不需要下放标记,

每次修改的时候找到完整区间,区间+1次%48

每次查询的时候,树上前缀和求当前区间已经经历了多少次被立方,输出对应的和

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define pb push_back
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
const int N=1e5+10,mod=99971;
int t,n,q,a[N],op,l,r;
struct segtree{
	int n;
	struct node{int l,r,add;ll v[49];}e[N<<2];
	#define l(p) e[p].l
	#define r(p) e[p].r
	#define a(p) e[p].add
	#define v(p,i) e[p].v[i]
	void up(int p){rep(i,0,47){v(p,i)=(v(p<<1,(i+a(p<<1))%48)+v(p<<1|1,(i+a(p<<1|1))%48))%mod;}}
	ll cal(ll x){return x*x*x%mod;}
	void bld(int p,int l,int r){
	    a(p)=0;
		l(p)=l;r(p)=r;
		if(l==r){v(p,0)=a[l]%mod;rep(i,1,47)v(p,i)=cal(v(p,i-1));return;}
		int mid=l+r>>1;
		bld(p<<1,l,mid);bld(p<<1|1,mid+1,r);
		up(p);
	}
	void init(int _n){n=_n;bld(1,1,n);}
	void chg(int p,int ql,int qr){
		if(ql<=l(p)&&r(p)<=qr){a(p)=(a(p)+1)%48;return;}
		int mid=l(p)+r(p)>>1;
		if(ql<=mid)chg(p<<1,ql,qr);
		if(qr>mid)chg(p<<1|1,ql,qr);
		up(p);
	}
	ll sum(int p,int ql,int qr,int x){
	    x=(x+a(p))%48;
		if(ql<=l(p)&&r(p)<=qr)return v(p,x);
		int mid=l(p)+r(p)>>1;ll res=0;
		if(ql<=mid)(res+=sum(p<<1,ql,qr,x))%=mod;
		if(qr>mid)(res+=sum(p<<1|1,ql,qr,x))%=mod;
		return res;
	}
}seg;
int main(){
    scanf("%d",&t);
    while(t--){
        scanf("%d%d",&n,&q);
        rep(i,1,n){
            scanf("%d",&a[i]);
        }
        seg.init(n);
        rep(i,1,q){
            scanf("%d%d%d",&op,&l,&r);
            if(op==1){
                seg.chg(1,l,r);
            }
            else{
                printf("%lld\n",seg.sum(1,l,r,0));
            }
        }
    }
    return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Code92007

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值