[zoj3813]Alternating Sum 公式化简,线段树

题意:给一个长度不超过100000的原串S(只包含数字0-9),令T为将S重复若干次首尾连接后得到的新串,有两种操作:(1)修改原串S某个位置的值(2)给定L,R,询问T中L<=i<=j<=R的G(i,j)的和,G(i,j)=Ti-Ti+1+Ti+2-Ti+3+...+(-1)j-iTj,L,R小于1e18

思路:从公式看不出用什么方法快速计算,不妨先对公式化简。令f(i)=(j:i->R)ΣG(i,j),则有:f(i)=G(i,i)+G(i,i+1)+...+G(i,R)  (a)

将 (a)的每一项展开,不难得到:f(i)=(R-i+1)*Ti - (R-i)*Ti+1 + (R-i-1)*Ti+3 +... + (-1)R-i*T

然后将f(i)求和,sum(L,R)=(i:L->R)Σf(i) = f(L) + f(L+1) + f(L+2) + ... + f(R),将每一项展开得到:

f(L)= (R-L+1)*T- (R-L)*TL+1 + (R-L-1)*TL+2 + ... + (-1)R-L*T

f(L+1)=           (R-L)*TL+1 - (R-L-1)*TL+2   - ...  + (-1)R-L-1*TR

 .

.

.

f(R-1)= 2TR-1   -  TR

f(R)= TR 

于是 sum(L,R)=(R-L+1)*TL + (R-L-1)*TL+2 + ... + 2TR-1 ,当R-L+1为偶数时

(R-L+1)*T+ (R-L-1)*TL+2 + ... + TR ,当R-L+1为奇数时

由于有修改操作,而sum(L,R) 可以比较容易的通过区间来合并,只需在线段树的每个区间[L,R]上记录四个值,var1表示从sum(L,R),var2表示sum(L+1,R),con1=TL + TL+2 + ... ,con2=TL+1 + TL+3 + ...,con1和con2在合并区间时需要用到,而左子区间长度为奇数会导致合并区间时右子区间需要从第二个数开始的sum值,所以需要记录sum(L+1,R)和con2。具体操作见代码。

到这里,问题并没解决,题目给的L,R太大,不过由于是重复原串S得到的串,肯定有快速计算重复部分的答案。对询问的区间左右边界定位,看是处在第几个S串里面,如果在同一个里面,直接算区间就行,如果跨多个S串,则答案由前缀、重复串、后缀这三部分组成,而重复串的值可以用快速幂的方法用logn次合并得到,每次合并都是O(1)的,三部分的值都出来后对这三部分进行合并即可。


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

#include <map>

#include <set>

#include <cmath>

#include <ctime>

#include <deque>

#include <queue>

#include <stack>

#include <vector>

#include <cstdio>

#include <string>

#include <cstdlib>

#include <cstring>

#include <iostream>

#include <algorithm>

using namespace std;

#define X                   first

#define Y                   second

#define pb                  push_back

#define mp                  make_pair

#define all(a)              (a).begin(), (a).end()

#define fillchar(a, x)      memset(a, x, sizeof(a))

typedef long long ll;

typedef pair<intint> pii;

typedef unsigned long long ull;

#ifndef ONLINE_JUDGE

void RI(vector<int>&a,int n){a.resize(n);for(int i=0;i<n;i++)scanf("%d",&a[i]);}

void RI(){}void RI(int&X){scanf("%d",&X);}template<typename...R>

void RI(int&f,R&...r){RI(f);RI(r...);}void RI(int*p,int*q){int d=p<q?1:-1;

while(p!=q){scanf("%d",p);p+=d;}}void print(){cout<<endl;}template<typename T>

void print(const T t){cout<<t<<endl;}template<typename F,typename...R>

void print(const F f,const R...r){cout<<f<<", ";print(r...);}template<typename T>

void print(T*p, T*q){int d=p<q?1:-1;while(p!=q){cout<<*p<<", ";p+=d;}cout<<endl;}

#endif

template<typename T>bool umax(T&a, const T&b){return b<=a?false:(a=b,true);}

template<typename T>bool umin(T&a, const T&b){return b>=a?false:(a=b,true);}

template<typename T>

void V2A(T a[],const vector<T>&b){for(int i=0;i<b.size();i++)a[i]=b[i];}

template<typename T>

void A2V(vector<T>&a,const T b[]){for(int i=0;i<a.size();i++)a[i]=b[i];}

const double PI = acos(-1.0);

const int INF = 1e9 + 7;

/* -------------------------------------------------------------------------------- */

template<int mod>

struct ModInt {

    const static int MD = mod;

    int x;

    ModInt(ll x = 0): x(x % MD) {}

    int get() { return x; }

    ModInt operator + (const ModInt &that) const int x0 = x + that.x; return ModInt(x0 < MD? x0 : x0 - MD); }

    ModInt operator - (const ModInt &that) const int x0 = x - that.x; return ModInt(x0 < MD? x0 + MD : x0); }

    ModInt operator * (const ModInt &that) const return ModInt((long long)x * that.x % MD); }

    ModInt operator / (const ModInt &that) const return *this * that.inverse(); }

    ModInt operator += (const ModInt &that) { x += that.x; if (x >= MD) x -= MD; }

    ModInt operator -= (const ModInt &that) { x -= that.x; if (x < 0) x += MD; }

    ModInt operator *= (const ModInt &that) { x = (long long)x * that.x % MD; }

    ModInt operator /= (const ModInt &that) { *this = *this / that; }

    ModInt inverse() const {

        int a = x, b = MD, u = 1, v = 0;

        while(b) {

            int t = a / b;

            a -= t * b; std::swap(a, b);

            u -= t * v; std::swap(u, v);

        }

        if(u < 0) u += MD;

        return u;

    }

};

typedef ModInt<1000000007> mint;

const int maxn = 1e5 + 7;

const int md = 1e9 + 7;

int a[maxn];

class SegTree {

    #define lson l, m, rt << 1

    #define rson m + 1, r, rt << 1 | 1

    struct Node {

        mint var1, var2, con1, con2;

    };

    Node tree[maxn << 2];

    int n;

    Node &merge(const Node &ul, const ll &Llen, const Node &ur, const ll &Rlen) {

        static Node ans;

        if (Llen & 1) {

            ans.var1 = ul.var1 + ur.var2 + ul.con1 * Rlen;

            ans.var2 = ul.var2 + ur.var1 + ul.con2 * Rlen;

            ans.con1 = ul.con1 + ur.con2;

            ans.con2 = ul.con2 + ur.con1;

        }

        else {

            ans.var1 = ul.var1 + ur.var1 + ul.con1 * Rlen;

            ans.var2 = ul.var2 + ur.var2 + ul.con2 * Rlen;

            ans.con1 = ul.con1 + ur.con1;

            ans.con2 = ul.con2 + ur.con2;

        }

        return ans;

    }

    void build(int l, int r, int rt) {

        if (l == r) {

            Node &u = tree[rt];

            u.var1 = u.con1 = a[l];

            u.var2 = u.con2 = 0;

            return ;

        }

        int m = (l + r) >> 1;

        build(lson);

        build(rson);

        int len = r - l + 1;

        tree[rt] = merge(tree[rt << 1], m - l + 1, tree[rt << 1 | 1], r - m);

    }

    void update(int p, int x, int l, int r, int rt) {

        if (l == r) {

            Node &u = tree[rt];

            u.var1 = u.con1 = x;

            u.var2 = u.con2 = 0;

            return ;

        }

        int m = (l + r) >> 1;

        if (p <= m) update(p, x, lson);

        else update(p, x, rson);

        tree[rt] = merge(tree[rt << 1], m - l + 1, tree[rt << 1 | 1], r - m);

    }

    Node query(int L, int R, int l, int r, int rt) {

        if (L <= l && r <= R) return tree[rt];

        int m = (l + r) >> 1;

        if (R <= m) return query(L, R, lson);

        if (L > m) return query(L, R, rson);

        Node ul = query(L, m, lson), ur = query(m + 1, R, rson);

        return merge(ul, m - L + 1, ur, R - m);

    }

    Node get(ll cnt) {

        if (cnt == 1) return tree[1];

        Node u = get(cnt >> 1);

        ll c = cnt >> 1;

        u = merge(u, c * n, u, c * n);

        if (cnt & 1) u = merge(u, c * n * 2, tree[1], n);

        return u;

    }

public:

    void build(int n) { this->n = n; build(1, n, 1); }

    void update(int p, int x) { update(p, x, 1, n, 1); }

    mint query(ll L, ll R) {

        ll lid = (L - 1) / n + 1, rid = (R - 1) / n + 1, dif = rid - lid;

        L = (L - 1) % n + 1;

        R = (R - 1) % n + 1;

        if (dif == 0) return query(L, R, 1, n, 1).var1;

        Node ul = query(L, n, 1, n, 1), ur = query(1, R, 1, n, 1);

        int Llen = n - L + 1, Rlen = R;

        mint var = ul.var1 + ul.con1 * ((dif - 1) * n + Rlen);

        if (dif - 1) {

            Node buf = get(dif - 1);

            if (Llen & 1) var += buf.var2 + buf.con2 * Rlen;

            else var += buf.var1 + buf.con1 * Rlen;

        }

        if ((Llen + (dif - 1) * n) & 1) var += ur.var2;

        else var += ur.var1;

        return var;

    }

};

SegTree st;

char s[maxn];

int main() {

#ifndef ONLINE_JUDGE

    freopen("in.txt""r", stdin);

    //freopen("out.txt", "w", stdout);

#endif // ONLINE_JUDGE

    int T, n, m, t;

    ll x, y;

    cin >> T;

    while (T --) {

        scanf("%*c%s", s);

        int n = strlen(s);

        for (int i = 0; i < n; i ++) {

            a[i + 1] = s[i] - ‘0‘;

        }

        st.build(n);

        cin >> m;

        while (m --) {

            scanf("%d%lld%lld", &t, &x, &y);

            if (t == 1) st.update(x, y);

            else printf("%d\n", st.query(x, y).get());

        }

    }

    return 0;

}

时间: 2024-10-11 21:48:17

[zoj3813]Alternating Sum 公式化简,线段树的相关文章

Codeforces 85D Sum of Medians(线段树)

85D Sum of Medians 题目链接 题意:一个集合有添加,删除元素,每次查询输出集合位置为i % 5 == 3的位置和 思路:线段树,线段树记录下% 5 == 0, 1, 2, 3, 4的和,并且记录一个mov表示右移多少,每次添加一个值的时候,就当前位置之后的一整段位置都要右移一个单位,这样去搞线段树维护一下即可 代码: #include <cstdio> #include <cstring> #include <cstdlib> #include <

【Educational Codeforces Round 37】F. SUM and REPLACE 线段树+线性筛

题意 给定序列$a_n$,每次将$[L,R]$区间内的数$a_i$替换为$d(a_i)$,或者询问区间和 这题和区间开方有相同的操作 对于$a_i \in (1,10^6)$,$10$次$d(a_i)$以内肯定可以最终化为$1$或者$2$,所以线段树记录区间最大值和区间和,$Max\le2$就返回,单点暴力更新,最后线性筛预处理出$d$ 时间复杂度$O(m\log n)$ 代码 #include <bits/stdc++.h> using namespace std; typedef long

codeforces CF920F SUM and REPLACE 线段树 线性筛约数

$ \Rightarrow $ 戳我进CF原题 F. SUM and REPLACE time limit per test: 2 seconds memory limit per test: 256 megabytes input: standard input output: standard output Let $ D(x) $ be the number of positive divisors of a positive integer $ x $ . For example, $

Educational Codeforces Round 72 (Rated for Div. 2)E. Sum Queries?(线段树区间合并)

https://codeforc.es/contest/1217/problem/E 建立9棵数位线段树维护区间最小值和次小值,建议用struct建树方便进行区间合并 1 #define bug(x) cout<<#x<<" is "<<x<<endl 2 #define IO std::ios::sync_with_stdio(0) 3 #include <bits/stdc++.h> 4 #define iter ::it

CF1217E Sum Queries? (线段树)

完了,前几天才说 edu 的 DEF 都不会,现在打脸了吧 qwq 其实在刚说完这句话 1min 就会了 D,3min 就会了 E 发现,对于大小 \(\ge 3\) 的不平衡集合,它至少有一个大小为 \(2\) 的子集是不平衡的. 证明,发现对于大小为 \(2\) 的集合,平衡当且仅当两数的数位交为空(对于任意一位,至多一个数在这一位上不是 \(0\)). 反证一波,如果大集合没有大小为 \(2\) 的不平衡集合,那么任意两数的数位交都为空,那么大集合也是平衡的,矛盾了. 所以,只需要考虑大小

[email&#160;protected] [307] Range Sum Query - Mutable / 线段树模板

Given an integer array nums, find the sum of the elements between indices i and j (i ≤ j), inclusive. The update(i, val) function modifies nums by updating the element at index i to val. Example: Given nums = [1, 3, 5] sumRange(0, 2) -> 9 update(1, 2

POJ 2886 Who Gets the Most Candies? 反素数+线段树

题意:变形的约瑟夫环模型,每个人有一个数字a,从第K个人开始出列,如果数字是正的,就往后数a个人出列,如果书负数,就往反方向数. 然后用最基本的线段树处理约瑟夫环的方法即可 但是题目要求的是第x个出列的人的名字,x为1-N中约数最多的数中的最小的那个.这里需要求反素数,即不大于N约数最多的. 写起来比较多,容易写错,一开始连素数打表都写作了QAQ #include <cstdio> #include <iostream> #include <cstring> #incl

&#183;专题」 线段树

PKU暑期培训第一天,这次培训人很多,但是感觉打酱油的也不少,不知道大牛有多少. 第一天都是讲线段树的,课件的话和往常一样,没什么变化. 具体的话,讲了线段树和树状数组.线段树的话讲了单点更新,成段更新,扫描线已经离散化. 然后随便提了提树状数组.估计明天再讲一点点,然后接着是讲并查集,多串匹配什么的. 线段树的题目我做得很少,以前看过HH大神的模板,想模仿来着,其实也没什么理解. 重新理解一下线段树吧. 线段树的用途,主要是维护区间问题,比如区间的单点更新操作,成段更新,扫描线等等.当然还有一

segment树(线段树)

线段树(segment tree)是一种Binary Search Tree或者叫做ordered binary tree.对于线段树中的每一个非叶子节点[a,b],它的左子树表示的区间为[a,(a+b)/2],右子树表示的区间为[(a+b)/2+1,b].如下图: [0-2] /       \ [0-1]          [2-2] /    \ [0-0]    [1-1] 下面看一道leetcode上的题,求动态区间的和(Range Sum Query - Mutable),题目如下: