ZOJ 4009

题目链接

题意:

维护一个数列,数列有两种操作:

1.将区间[L,R]中的每个数都变成3次方,即a[i] --> a[i]*a[i]*a[i]

2.询问区间[L,R]的和(取模99971)

思路:

打表可以发现所有数字在取模的情况下循环节的最小公倍数为48,故维护一个48倍内容的线段树。

更新可以在对应区间节点处打上更新标记,向上维护时可以将其看出更新偏转,向下询问定义一个变量保存更新次数,最后输出。

总结:

写题目应该养成二维数组数字较大维在前的习惯

#include<bits/stdc++.h>
using namespace std;
#define lson rt<<1
#define rson rt<<1|1
typedef long long LL;
const int maxn = 100010;
const int mod  =  99971;
int sum[maxn<<2][50],cnt[maxn<<2];
void push_up( int rt )
{
    for ( int i=0 ; i<48 ; i++ )
        sum[rt][i] = (sum[lson][(i+cnt[lson])%48]+sum[rson][(i+cnt[rson])%48])%mod;
}
void build( int l , int r , int rt )
{
    cnt[rt] = 0;
    if ( l==r )
    {
        scanf ( "%d" , &sum[rt][0] );
        sum[rt][0] %= mod;
        for ( int i=1 ; i<48 ; i++ )
            sum[rt][i] = 1LL*sum[rt][i-1]*sum[rt][i-1]*sum[rt][i-1]%mod;
        return;
    }
    int mid = ( l+r )>>1;
    build ( l , mid , lson );
    build ( mid+1 , r , rson );
    push_up( rt );
}
void update( int L , int R , int l , int r , int rt )
{
    if ( L<=l&&R>=r )
    {
        cnt[rt]++;
        return;
    }
    int mid = ( l+r )>>1;
    if ( L<=mid ) update( L , R , l , mid , lson );
    if ( R> mid ) update( L , R , mid+1 , r , rson );
    push_up ( rt );
}
int query( int L , int R , int l , int r , int rt , int x )
{
    x = ( x+cnt[rt] )%48;
    if ( L<=l&&R>=r ) return sum[rt][x];
    int mid = ( l+r )>>1,res = 0;
    if ( L<=mid ) res += query( L , R , l , mid , lson , x );
    if ( R> mid ) res += query( L , R , mid+1 , r , rson , x );
    return res%mod;
}
int main()
{
    int T; scanf ( "%d" , &T );
    for ( int cas=1 ; cas<=T ; cas++ )
    {
        int n,m; scanf ( "%d%d" , &n , &m );
        build( 1 , n , 1 );
        for ( int i=1 ; i<=m ; i++ )
        {
            int op,l,r; scanf( "%d%d%d" , &op , &l , &r );
            if ( op==1 ) update( l , r , 1 , n , 1 );
            else printf ( "%d\n" , query( l , r , 1 , n , 1 , 0 ) );
        }
    }
	return 0;
}

 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值