zoukankan      html  css  js  c++  java
  • [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 ", st.query(x, y).get());
            }
        }
        return 0;
    }


  • 相关阅读:
    C语言,C++,static
    英语自我介绍
    总线接口与计算机通信(五)CAN总线
    总线接口与计算机通信(二)SPI总线
    总线接口与计算机通信(一)I2C总线
    总线接口与计算机通信
    C语言函数指针
    服务器体系(SMP, NUMA, MPP)与共享存储器架构(UMA和NUMA)
    实时调度类
    Linux CFS调度器之唤醒抢占--Linux进程的管理与调度(三十)
  • 原文地址:https://www.cnblogs.com/jklongint/p/4714494.html
Copyright © 2011-2022 走看看