Codeforces 316 E3 线段树

题目链接


题意

给定一个长度为\(n\)序列\(a\),需要支持如下操作

  • 单点修改
  • 对于区间\([l..r]\),求\(\sum_{i=0}^{r-l}f_i*a_{l+i}\),模\(10^9\),其中\(f\)是斐波那契数列,\(f_0=f_1=1\)
  • 区间加

做法

建线段树,对于一个节点\([l..r]\),记

\[s_k=\sum_{i=0}^{r-l}f_{i+k}*a_{l+i}\]

存在以下性质
\[
\begin{align}
&s_{k-2}+s_{k-1}\=&\sum_{i=0}^{r-l}(f_{i+k-2}+f_{i+k-1})*a_{l+i}\=&\sum_{i=0}^{r-l}f_{i+k}*a_{l+i}\=&s_k
\end{align}
\]

只需要维护\(s_0\)和\(s_1\),预处理斐波那契数列作为系数,可以\(O(1)\)求出\(s_k\)

合并两个区间的时候,需要求出第二个区间的\(s_{len},s_{len+1}\),其中\(len\)是第一个区间的长度

区间加,可以利用\[\sum_{i=0}^nf_i=f_{n+2}-1\]快速修改

#include<cstdio>
#include<algorithm>
#include<ctype.h>
#include<string.h>
#include<math.h>

using namespace std;
#define ll long long

inline char read() {
    static const int IN_LEN = 1000000;
    static char buf[IN_LEN], *s, *t;
    return (s == t ? t = (s = buf) + fread(buf, 1, IN_LEN, stdin), (s == t ? -1 : *s++) : *s++);
}
template<class T>
inline void read(T &x) {
    static bool iosig;
    static char c;
    for (iosig = false, c = read(); !isdigit(c); c = read()) {
        if (c == '-') iosig = true;
        if (c == -1) return;
    }
    for (x = 0; isdigit(c); c = read()) x = ((x + (x << 2)) << 1) + (c ^ '0');
    if (iosig) x = -x;
}
const int OUT_LEN = 10000000;
char obuf[OUT_LEN], *ooh = obuf;
inline void print(char c) {
    if (ooh == obuf + OUT_LEN) fwrite(obuf, 1, OUT_LEN, stdout), ooh = obuf;
    *ooh++ = c;
}
template<class T>
inline void print(T x) {
    static int buf[30], cnt;
    if (x == 0) print('0');
    else {
        if (x < 0) print('-'), x = -x;
        for (cnt = 0; x; x /= 10) buf[++cnt] = x % 10 + 48;
        while (cnt) print((char)buf[cnt--]);
    }
}
inline void flush() { fwrite(obuf, 1, ooh - obuf, stdout); }
const int N = 200005, P = 1000000000;
int n, m, f[N], a[N], lazy[N<<2];
struct st{
    int a, b, len;
    inline st(){}
    inline st(int a_, int b_, int len_){ a=a_, b=b_, len=len_;}
    inline st operator *(const st &rhs)const{
        return st((a+(ll)rhs.a*f[len-1]+(ll)rhs.b*f[len])%P, (b+(ll)rhs.a*f[len]+(ll)rhs.b*f[len+1])%P, len+rhs.len);
    }
}s[N<<2];
void build(int l, int r, int t){
    if(l==r) return (void)(s[t].a=s[t].b=a[l], s[t].len=1);
    int mid=l+r>>1, k=t<<1;
    build(l, mid, k), build(mid+1, r, k|1);
    s[t]=s[k]*s[k|1];
}
inline void add(int t, int x){
    (lazy[t]+=x)%=P;
    s[t].a=(s[t].a+(ll)(f[s[t].len+2]-1)*x)%P;
    s[t].b=(s[t].b+(ll)(f[s[t].len+3]-2)*x)%P;
}
void modify(int l, int r, int t, int x, int y){
    if(l==r) return (void)(s[t].a=s[t].b=y);
    int mid=l+r>>1, k=t<<1;
    if(lazy[t]) add(k, lazy[t]), add(k|1, lazy[t]), lazy[t]=0;
    if(x<=mid) modify(l, mid, k, x, y); else modify(mid+1, r, k|1, x, y);
    s[t]=s[k]*s[k|1];
}
st query(int l, int r, int t, int L, int R){
    if(L<=l && r<=R) return s[t];
    int mid=l+r>>1, k=t<<1;
    if(lazy[t]) add(k, lazy[t]), add(k|1, lazy[t]), lazy[t]=0;
    if(R<=mid) return query(l, mid, k, L, R);
    if(L>mid) return query(mid+1, r, k|1, L, R);
    return query(l, mid, k, L, R)*query(mid+1, r, k|1, L, R);
}
void change(int l, int r, int t, int L, int R, int x){
    if(L<=l && r<=R) return add(t, x);
    int mid=l+r>>1, k=t<<1;
    if(lazy[t]) add(k, lazy[t]), add(k|1, lazy[t]), lazy[t]=0;
    if(L<=mid) change(l, mid, k, L, R, x);
    if(R>mid) change(mid+1, r, k|1, L, R, x);
    s[t]=s[k]*s[k|1];
}
int main() {
    read(n), read(m);
    f[1]=f[2]=1;
    for(int i=3; i<=n+3; ++i) f[i]=(f[i-1]+f[i-2])%P;
    for(int i=1; i<=n; ++i) read(a[i]);
    build(1, n, 1);
    while(m--){
        static int opt, l, r, x;
        read(opt), read(l), read(r);
        if(opt==1) modify(1, n, 1, l, r);
        else if(opt==2) print(query(1, n, 1, l, r).a), print('\n');
        else read(x), change(1, n, 1, l, r, x);
    }
    return flush(), 0;
}

原文地址:https://www.cnblogs.com/CMXRYNP/p/9651026.html

时间: 2024-10-14 11:05:11

Codeforces 316 E3 线段树的相关文章

CodeForces 46DParking Lot线段树

#include <cstdio> #include <cstring> #include <algorithm> #include <climits> #include <string> #include <iostream> #include <map> #include <cstdlib> #include <list> #include <set> #include <qu

Codeforces 19D Points 线段树+set

题目链接:点击打开链接 线段树维护y值大于val的最小x值 #include <cstdio> #include <cstring> #include <algorithm> #include <vector> #include <iostream> #include <map> #include <set> #include <math.h> using namespace std; #define inf

Codeforces 444C(线段树)

区间颜色不一致就更新到底,否则lazy标记 #include<cstdio> #include<cstring> #include<cmath> #include<queue> using namespace std; #define lc l,m,index<<1 #define rc m+1,r,index<<1|1 #define N 100005 #define ll __int64 struct node { bool sa

New Year and Old Subsequence CodeForces - 750E(线段树 + 矩阵)

New Year and Old Subsequence (CodeForces - 750E) 题意: 给出一个长度为\(N\)的数字串,\(q\)次询问.每次询问一段区间.在区间内删除尽量少的字符,使得区间内含有序列"\(2017\)",且不含有"\(2016\)". \(n,q<=200000\). 题解: 用\(01234\)五种状态分别表示"". "\(2\)"."\(20\)"."

Sum Queries? CodeForces - 1217E (线段树)

Sum Queries? CodeForces - 1217E (线段树) 题意: 定义一个集合为\(balanced\)的,当且仅当集合内数字之和的每个十进制位,都与集合中某个数该位相同.否则,称该集合为\(unbalanced\)的. 给定一个长度为\(n\)的序列,\(q\)次询问一个区间内数字之和最小的\(unbalanced\)集合,输出数字之和.若没有输出\(-1\). \(n,q<=200000\). 题解: 可以发现,如果存在\(unbalanced\)集合,那么最小的一定是只两

CodeForces 383C-dfs序-线段树

题意:一棵根为1的多叉树有n个点,题目有m次询问.第一行输入n和m,第二行输入n-1条边, 以后m行输入操作,操作有两种:1 x val 表示 节点的值x+val,同时它的儿子层节点的值-val,孙子层节点的值+val...如此往下直到叶子节点:2 x 表示输出x节点的当前值. 思路:类似poj3321,用dfs序重新表示每个节点,这样更新子树的操作就变成更新区间了,区间是:[i, i+cnt][当前节点的dfs序为 i, 儿子数为cnt],查询同理,单点查询当前节点的dfs序.但是这道题的df

【题解】Berland.Taxi Codeforces 883L 模拟 线段树 堆

Prelude 题目传送门:ヾ(?ω?`)o Solution 按照题意模拟即可. 维护一个优先队列,里面装的是正在运营中的出租车,关键字是乘客的下车时间. 维护一个线段树,第\(i\)个位置表示第\(i\)个房子前面有没有停放出租车,这样在有人需要打车的时候可以快速找到离她最近的车的位置. 对每个房子维护一个堆,里面装的是停在这个房子前面的出租车,关键字是出租车的编号和上一个乘客下车的时间,上一个乘客下车越早,等待时间越长. 然后模拟时间的流逝就可以了,代码非常好写. Code #includ

Codeforces 787D. Legacy 线段树优化建图+最短路

output standard output Rick and his co-workers have made a new radioactive formula and a lot of bad guys are after them. So Rick wants to give his legacy to Morty before bad guys catch them. There are n planets in their universe numbered from 1 to n.

Codeforces.1051G.Distinctification(线段树合并 并查集)

题目链接 \(Description\) 给定\(n\)个数对\(A_i,B_i\).你可以进行任意次以下两种操作: 选择一个位置\(i\),令\(A_i=A_i+1\),花费\(B_i\).必须存在一个位置\(j\),满足\(A_i=A_j,\ i\neq j\),才可以进行. 选择一个位置\(i\),令\(A_i=A_i-1\),花费\(-B_i\).必须存在一个位置\(j\),满足\(A_i=A_j+1\),才可以进行. 你需要对于所有\(i\in[1,n]\),求使得\(A_1,A_2,