线段树yy (线段树维护等比数列的和)

没有题目链接

一个长度为 n 的序列,Q 次操作:

  1. 对于区间 l 到 r 的所有位置 i, a [ i ] + = b i − l a[i]+=b^{i - l} a[i]+=bil
  2. 求区间 l 到 r 的和 mod 1e9 + 7

对于所有操作,b 不变。(1 <= n, Q <= 1e5, 1 < b <= 1e9)

题解:
由于每次加的是一个等比数列,那么可以将等比数列的首项作为下传标记更新。
由于没有交题的地方,就自己写了个对拍程序QAQ,和一位大佬的代码对拍。(附上源代码和对拍程序,如有错误欢迎指出)
图片
对拍结果 100% 的代码:

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef unsigned long long ull;
#define int ll
#define PI acos(-1.0)
#define INF 0x3f3f3f3f3f3f3f3f
#define P pair<int, int>
#define fastio ios::sync_with_stdio(false), cin.tie(0)
const int mod = 1e9 + 7;
const int M = 1000000 + 10;
const int N = 100000 + 10;

long long mulmod(long long n, long long m)
{
    n %= mod, m %= mod;
    return (n * m - (long long)((long double)n / mod * m) * mod + mod) % mod;
}

int powmod(int n, int m)
{
    int ans = 1;
    while(m) {
        if(m & 1) ans = mulmod(ans, n) % mod;
        n = mulmod(n, n) % mod;
        m >>= 1;
    }
    return ans % mod;
}

int n, q, b;
int tree[N<<2], add[N<<2];
int pow_q[N], inv;

int sum(int a1, int num)
{
    return mulmod(mulmod(a1, (pow_q[num] - 1)), inv);
}

void build(int l = 1, int r = n, int rt = 1)
{
    if(l == r) {
        scanf("%lld", &tree[rt]);
        return ;
    }
    int mid = (l + r) >> 1;
    build(l, mid, rt << 1);
    build(mid + 1, r, rt << 1 | 1);
    tree[rt] = (tree[rt << 1] + tree[rt << 1 | 1]) % mod;
}

void push(int l, int r, int rt)
{
    if(add[rt]) {
        int mid = (l + r) >> 1, temp;
        add[rt << 1] = (add[rt << 1] + add[rt]) % mod;
        add[rt << 1 | 1] = (add[rt << 1 | 1] + (temp = add[rt] * pow_q[mid - l + 1] % mod)) % mod;
        tree[rt << 1] = (tree[rt << 1] + sum(add[rt], mid - l + 1)) % mod;
        tree[rt << 1 | 1] = (tree[rt << 1 | 1] + sum(temp, r - mid)) % mod;
        add[rt] = 0;
    }
}

void update(int L, int R, int l = 1, int r = n, int rt = 1)
{
    if(L <= l && r <= R) {
        int a1 = pow_q[l - L];
        tree[rt] = (tree[rt] + sum(a1, r - l + 1)) % mod;
        add[rt] += a1;
        return ;
    }
    push(l, r, rt);
    int mid = (l + r) >> 1;
    if(L <= mid) update(L, R, l, mid, rt << 1);
    if(mid < R) update(L, R, mid + 1, r, rt << 1 | 1);
    tree[rt] = (tree[rt << 1] + tree[rt << 1 | 1]) % mod;
}

int query(int L, int R, int l = 1, int r = n, int rt = 1)
{
    if(L <= l && r <= R) return tree[rt];
    push(l, r, rt);
    int mid = (l + r) >> 1, ans = 0;
    if(L <= mid) ans = (ans + query(L, R, l, mid, rt << 1)) % mod;
    if(mid < R) ans = (ans + query(L, R, mid + 1, r, rt << 1 | 1)) % mod;
    return ans;
}

void pre()
{
    inv = powmod(b - 1, mod - 2);
    pow_q[0] = 1;
    for(int i = 1; i <= n; i ++) {
        pow_q[i] = pow_q[i - 1] * b % mod;
    }
    build();
}

signed main()
{
    freopen("in.in", "r", stdin);
    freopen("txb.out", "w", stdout);
    scanf("%lld %lld %lld", &n, &q, &b);
    pre();
    for(int i = 1, op, l, r; i <= q; i ++) {
        scanf("%lld %lld %lld", &op, &l, &r);
        if(op == 1) {
            update(l, r);
        } else {
            printf("%lld\n", query(l, r));
        }
    }
    return 0;
}

/*

  Rejoicing in hope, patient in tribulation.

*/

随机生成数据程序:(数据量都是最大值)

#include<bits/stdc++.h>
using namespace std;

const int maxn=1e5;
const int qq=1e9;
const int mod=1e9+7;

int main(){
    int n,m,q,id,l,r;
    freopen("in.in","w",stdout);
    srand(unsigned(time(0)));
    n=maxn;
    m=maxn;
    q=qq;
    if(q<=1) q=2;
    printf("%d %d %d\n",n,m,q);
    for(int i=1;i<=n;++i)
        printf("%d ",rand()%qq);
    printf("\n");
    while(m--){
        id=rand()%2+1;
        l=rand()%n+1;
        r=rand()%n+1;
        if(l>r) swap(l,r);
        printf("%d %d %d\n",id,l,r);
    }

    return 0;
}

判题程序:

#include <bits/stdc++.h>
using namespace std;

int main() {
    for (int T = 1; T <= 20; T++) {
        system("random.exe");
        clock_t st,ed;
        st = clock();
        system("txb.exe");
        ed = clock();
        system("cy.exe");
        if (system("fc txb.out cy.out")) {
            printf("Wrong Answer on test %d", T);
            return 0;
        }
        else {
            printf("Accepted, 测试点 #%d, 用时 ", T); cout << ed - st << "ms" << endl;
        }
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值