线段树(区间合并)

    xiaoxiao2022-07-06  182

    题目:https://hihocoder.com/problemset/problem/1116

     

    描述

    现在有一个有n个元素的数组a1, a2, ..., an。

    记f(i, j) = ai * ai+1 * ... * aj。

    初始时,a1 = a2 = ... = an = 0,每次我会修改一个ai的值,你需要实时反馈给我 ∑1 <= i <= j <= n f(i, j)的值 mod 10007。

    输入

    第一行包含两个数n(1<=n<=100000)和q(1<=q<=500000)。

    接下来q行,每行包含两个数i, x,代表我把ai的值改为了x。

    输出

    分别输出对应的答案,一个答案占一行。

    样例输入

    5 5 1 1 2 1 3 1 4 1 5 1

    样例输出

    1 3 6 10 15

    题意:

            求区间(1,n)的所有子区间的连乘的和;

    思路:

         线段数,这题如果用用线段树做不会的会可能就是不会合并两个区间;

          对于线段树的每一个节点,我们保持这个区间的答案(ans),前缀连乘和(ls),后缀连乘和,以及连乘(mul);

          对于每个节点我们可以这样合并:

    至于为什么可以这样,自己举两三个数来看一看就很清楚了;

    #include<bits/stdc++.h> using namespace std; #define mod 10007 const int maxn = 100 * 1000 + 10; int n,q; struct { struct { int L, R; int ls, rs, mul, ans; }tree[maxn<<2]; void join(int rt) { tree[rt].ans = (tree[rt << 1].ans + tree[rt << 1 | 1].ans + tree[rt << 1].rs*tree[rt << 1 | 1].ls) % mod; tree[rt].ls = (tree[rt<<1].ls + tree[rt << 1].mul*tree[rt << 1 | 1].ls) % mod; tree[rt].rs = (tree[rt<<1|1].rs + tree[rt << 1|1].mul*tree[rt << 1].rs) % mod; tree[rt].mul = (tree[rt << 1].mul*tree[rt<<1|1].mul)%mod; } void build(int s,int L,int R) { tree[s].L = L; tree[s].R = R; tree[s].ls = tree[s].rs = tree[s].ans = tree[s].ans = 0; if (L == R)return; int mid = (L + R)>>1; build(s<<1,L,mid); build(s<<1|1,mid+1,R); } void change(int rt, int pos,int x) { if (tree[rt].L==tree[rt].R) { tree[rt].ls = tree[rt].rs = tree[rt].mul = tree[rt].ans = x; return; } int mid = (tree[rt].L + tree[rt].R) >> 1; if (pos <= mid)change(rt<<1,pos,x); else change(rt << 1 | 1, pos, x); join(rt); } }T; int main() { ios::sync_with_stdio(false); cin >> n >> q; int p, x; T.build(1,1,n); while (q--) { cin >> p >> x; T.change(1,p,x); cout << T.tree[1].ans<<endl; } return 0; }

     

    最新回复(0)