牛客挑战赛39 C牛牛的等差数列

牛牛的等差数列

由于是每个区间都要加上一个等差数列,而又因为等差数列的第 i i i项可以直接得到 ,等差数列+等差数列依旧是等差数列。
具有可加性,所以可以用线段树来维护,那么我们每个节点维护的的信息有区间和 s u m sum sum,区间首项 f f ff ff,区间公差 d d dd dd
最后查询就直接查询 s u m sum sum,那么我们区间的首项和区间的公差又怎么维护,每个节点都只能维护一段区间,比如下面这种去情况:
牛客挑战赛39 C牛牛的等差数列_第1张图片
[ L , R ] [L,R] [L,R]是要更新的区间,首项为 a a a,公差为 d d d,但是在线段树中被分成了3部分,很明显,在第①段区间里,它对应的首项和公差分别是 a , d a,d a,d,那么第②段,我们可以把它看成单独的一个等差数列,首项为 a + l e n 1 ∗ d a+len_1*d a+len1d(就是原等差数列的位置对应的值),然后公差为 d d d,这样就把他们分成互不干扰的几段区间了。然后这个区间的 s u m = a ∗ l e n + l e n ∗ ( l e n − 1 ) / 2 ∗ d sum = a*len + len * (len-1)/2*d sum=alen+len(len1)/2d,首项算了len次,d算了(1+2+3+…len-1)次。然后对于pushdown,也类似。
对于取模:因为每次取模都不一样,如果单独来算比较复杂,我们直接先mod他们的lcm,然后最后query的时候mod对应的数就好了,因为lcm的倍数也是它们的倍数。

#pragma GCC optimize(2)
#include
using namespace std;
const int man = 2e5+10;
#define IOS ios::sync_with_stdio(0)
template <typename T>
inline T read(){T sum=0,fl=1;int ch=getchar();
for(;!isdigit(ch);ch=getchar())if(ch=='-')fl=-1;
for(;isdigit(ch);ch=getchar())sum=sum*10+ch-'0';
return sum*fl;}
template <typename T>
inline void write(T x) {static int sta[35];int top=0;
do{sta[top++]= x % 10, x /= 10;}while(x);
while (top) putchar(sta[--top] + 48);}
template<typename T>T gcd(T a, T b) {return b==0?a:gcd(b, a%b);}
template<typename T>T exgcd(T a,T b,T &g,T &x,T &y){if(!b){g = a,x = 1,y = 0;}
else {exgcd(b,a%b,g,y,x);y -= x*(a/b);}}
#ifndef ONLINE_JUDGE
#define debug(fmt, ...) {printf("debug ");printf(fmt,##__VA_ARGS__);puts("");}
#else
#define debug(fmt, ...)
#endif
typedef unsigned long long ll;
const ll mod = 3ll*5*7*11*13*17*19*23;
int a[man];
int flag[man<<2];
ll sum[man<<2],dd[man<<2],ff[man<<2];

void pushup(int rt){
    sum[rt] = (sum[rt<<1] + sum[rt<<1|1])%mod;
}

void pushdown(int rt,int l_len,int r_len){
    if(flag[rt]){
        flag[rt<<1|1] = flag[rt<<1] = 1;
        ff[rt<<1] = (ff[rt<<1] + ff[rt]) % mod;
        dd[rt<<1] = (dd[rt<<1] + dd[rt]) % mod;
        sum[rt<<1] = (sum[rt<<1] + ff[rt] * l_len % mod + 1ull * l_len * (l_len-1) / 2 % mod * dd[rt])%mod;
        
        ff[rt<<1|1] = (ff[rt<<1|1] + ff[rt] + l_len * dd[rt]) % mod;//ff[rt] + l_len * dd[rt]为父区间对应下来的首项
        dd[rt<<1|1] = (dd[rt<<1|1] + dd[rt])%mod;
        sum[rt<<1|1] = (sum[rt<<1|1] + (ff[rt] + l_len * dd[rt])*r_len % mod + 1ull * r_len * (r_len-1) / 2 % mod * dd[rt])%mod;
        dd[rt] = ff[rt] = flag[rt] = 0;
    }
}

void build(int l,int r,int rt){
    sum[rt] = flag[rt] = dd[rt] = ff[rt] = 0;
    if(l==r){
        sum[rt] = a[l] % mod;
        return;
    }
    int m = l + r >> 1;
    build(l,m,rt<<1);
    build(m+1,r,rt<<1|1);
    pushup(rt);
}

void update(int l,int r,int L,int R,int rt,int va,int d){
    if(L<=l&&R>=r){
        flag[rt] = 1;
        ff[rt] = (ff[rt] + va + 1ull * (l - L) * d )%mod;// va + 1ull * (l - L) * d 为L,R区间相应位置所对应的区间
        dd[rt] = (dd[rt] + 1ull * d) % mod; 
        sum[rt] = (sum[rt] + 1ull * (va + 1ull * (l - L) * d) * (r-l+1) % mod ) % mod;//与上面相对应
        sum[rt] = (sum[rt] + 1ull * (r - l + 1) * (r - l) / 2 * d % mod) % mod; 
        return;
    }
    int m = l + r >> 1;
    pushdown(rt,m-l+1,r-m);
    if(L<=m)update(l,m,L,R,rt<<1,va,d);
    if(R>m)update(m+1,r,L,R,rt<<1|1,va,d);
    pushup(rt);
}

void query(int l,int r,int L,int R,int rt,int &ans,int mod){
    if(L<=l&&R>=r){
        ans = (ans + sum[rt]%mod)%mod;
        //printf("query---:sum[%d] = %llu\n",rt,sum[rt]);
        return;
    }
    int m = l + r >> 1;
    pushdown(rt,m-l+1,r-m);
    if(L<=m)query(l,m,L,R,rt<<1,ans,mod);
    if(R>m)query(m+1,r,L,R,rt<<1|1,ans,mod);
    pushup(rt);
}

void print(int l,int r,int rt){
    printf("sum[%d] = %llu\n",rt,sum[rt]);
    if(l==r){
        return;
    }
    int m = l + r >> 1;
    pushdown(rt,m-l+1,r-m);
    print(l,m,rt<<1);
    print(m+1,r,rt<<1|1);
    pushup(rt);
}

int main() {
    #ifndef ONLINE_JUDGE
        //freopen("in.txt", "r", stdin);
        //freopen("out.txt","w",stdout);
    #endif
    int n;
    scanf("%d",&n);
    for(int i = 1;i <= n;i++){
        scanf("%d",a+i);
    }   
    build(1,n,1);
    int q;
    scanf("%d",&q);
    int op,l,r,val,d,m,ans;
    while(q--){ 
       // print(1,n,1);
        scanf("%d%d%d",&op,&l,&r);
        if(1==op){
            scanf("%d%d",&val,&d);
            update(1,n,l,r,1,val,d);
        }else if(2==op){
            scanf("%d",&m);
            ans = 0;
            query(1,n,l,r,1,ans,m);
            printf("%d\n",ans);
        }
    }
    return 0;
}

你可能感兴趣的:(牛客,数据结构,线段树)