题意:给一个长度不超过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;
}

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

  1. codeforces 1217E E. Sum Queries? (线段树

    codeforces 1217E E. Sum Queries? (线段树 传送门:https://codeforces.com/contest/1217/problem/E 题意: n个数,m次询问 ...

  2. Yandex.Algorithm 2011 Round 1 D. Sum of Medians 线段树

    题目链接: Sum of Medians Time Limit:3000MSMemory Limit:262144KB 问题描述 In one well-known algorithm of find ...

  3. Codeforces 85D Sum of Medians(线段树)

    题目链接:Codeforces 85D - Sum of Medians 题目大意:N个操作,add x:向集合中加入x:del x:删除集合中的x:sum:将集合排序后,将集合中全部下标i % 5 ...

  4. 【BZOJ4262】Sum 单调栈+线段树

    [BZOJ4262]Sum Description Input 第一行一个数 t,表示询问组数. 第一行一个数 t,表示询问组数. 接下来 t 行,每行四个数 l_1, r_1, l_2, r_2. ...

  5. 【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) ...

  6. CF1217E Sum Queries? (线段树)

    完了,前几天才说 edu 的 DEF 都不会,现在打脸了吧 qwq 其实在刚说完这句话 1min 就会了 D,3min 就会了 E 发现,对于大小 \(\ge 3\) 的不平衡集合,它至少有一个大小为 ...

  7. 【11.5校内测试】【倒计时5天】【DP】【二分+贪心check】【推式子化简+线段树】

    Solution 非常巧妙的建立DP方程. 据dalao们说题目明显暗示根号复杂度??(反正我是没看出来 因为每次分的块大小一定不超过$\sqrt n$,要不然直接每个位置开一个块答案都才为$n$. ...

  8. codeforces 85D D. Sum of Medians 线段树

    D. Sum of Medians time limit per test 3 seconds memory limit per test 256 megabytes input standard i ...

  9. leetcode@ [307] Range Sum Query - Mutable / 线段树模板

    Given an integer array nums, find the sum of the elements between indices i and j (i ≤ j), inclusive ...

随机推荐

  1. Python - 关于带参数的装饰器的理解

    [原创]转载请注明作者Johnthegreat和本文链接 关于装饰器的理解,特别像<盗梦空间>中的进入梦境和从梦境出来的过程,一层一层的深入梦境,然后又一层一层的返回,被带入梦境的是被装饰 ...

  2. Fiddler抓取抖音视频

    目录 工具 Fiddler配置 手机端配置 工具 Android 或 ios手机均可 Fiddler 下载地址:https://www.telerik.com/fiddler Windows 操作系统 ...

  3. [WPF] 考古Expression Web:微软当年最漂亮的WPF软件

    1. 什么是Expression Web Expression Studio是微软在2007年推出的一套针对设计师的套件,其中包含专业的设计工具和新技术,可以弹性且自由地将设计方案转为实际--无论设计 ...

  4. Elasticsearch 集群部署

    本文部署环境 $ cat /etc/redhat-release CentOS Linux release (Core) 部署前系统优化 $ /etc/security/limits.conf roo ...

  5. AIX详细的VG,LV扩容步骤

    需求 1.归档日志刷得太快,经常把空间挤爆. 2.Oracle数据库表空间需要扩容 解决方案 1.先做重要数据备份 2.进行文件系统扩容 步骤 1. df -g 查找出/u01 对应的VG卷 VOLU ...

  6. Swoole 实战:MySQL 查询器的实现(协程连接池版)

    目录 需求分析 使用示例 模块设计 UML 类图 入口 事务 连接池 连接 查询器的组装 总结 需求分析 本篇我们将通过 Swoole 实现一个自带连接池的 MySQL 查询器: 支持通过链式调用构造 ...

  7. 【Linux题目】第五关

    1. 如何取得/etiantian文件的权限对应的数字内容,如-rw-r-r 为644,要求使用命令取得644或0644这样的数字. 解答: 方法1:用sed获取stat filename里的属性值 ...

  8. 【linux三剑客】sed命令

    sed - stream editor for filtering and transforming text sed 流编辑器 strem edition,实现对文件的增删改替换查是Linux中第二 ...

  9. 自定义View之Canvas使用

    自定义View的绘制流程一般都是这样:提前创建好Paint对象,重写onDraw(),把绘制代码卸载ondraw()里面,大致如下: Paint paint = new Paint(); @Overr ...

  10. Linux笔记(shell基础,历史命令,命令补全/别名,通配符,输出重定向)

    一.shell 基础 shell是个命令解释器,提供用户和机器之间的交互 每个用户都可以拥有自己特定的shell centos7默认Shell为bash(Bourne Agin shell) 除了ba ...