[CF718C]Sasha and Array(线段树+矩阵快速幂)

题目链接:https://codeforces.com/contest/718/problem/C

题意:给出一个序列,有两种操作,操作一:将序列中l-r部分的值加上某个数,操作二:计算Σri=lf(i) 的值第l-r项斐波那契数的和。

思路:首先我们需要解决的问题是计算第n项斐波那契数的值,n的范围的1e9,不难想到,我们可以通过使用矩阵快速幂(时间复杂度logn)来计算,其次,还有一个问题,如何进行区间修改,在我们算出第n项斐波那契数的矩阵时,我们要求在区间每个数都加上x之后的值,那么我们只需要用此区间和的矩阵乘上x的斐波那契数矩阵(这是一个结论,不难总结),大概就是假设区间和是f(2) + f(3),那么乘上x矩阵,就等于f(2) * x + f(3) * x,两者结果是相等的,而矩阵乘就等于下标相加,所以得出此结论,还要注意的是矩阵的初始值要设为单位矩阵,否则会在之后矩阵相乘运算中变成零。

AC代码:

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<algorithm>
  4 #include<cmath>
  5 #include<cstring>
  6 #define int long long
  7 #define ll long long
  8 using namespace std;
  9 //const int N = 100010;
 10 const int mod = 1e9 + 7;
 11 const int N = 2;
 12 const int Maxn = 1e5 + 10;
 13 
 14 int n = 2;
 15 
 16 struct Matrix {
 17 
 18     int x[N][N];
 19     void init() {
 20         x[0][0] = x[1][0] = x[0][1] = 1;
 21         x[1][1] = 0;
 22     }
 23     void unit() {
 24         memset(x, 0, sizeof(x));
 25         for (int i = 0; i < N; i++) {
 26             x[i][i] = 1;
 27         }
 28     }
 29     int flag = 1;
 30     void clear() {
 31         memset(x, 0, sizeof(x));
 32         flag = 0;
 33     }
 34     bool empty() {
 35         if (!x[0][0] && !x[0][1] && !x[1][0] && !x[1][1]) return true;
 36         else return false;
 37     }
 38 
 39 };
 40 Matrix operator * (const Matrix& m1,const Matrix& m2) {
 41 
 42     Matrix ans;
 43     for (int i = 0; i < n; i++) {
 44         for (int j = 0; j < n; j++) {
 45             int tmp = 0;
 46             for (int k = 0; k < n; k++) {
 47                 tmp = (tmp + (m1.x[i][k] * m2.x[k][j]) % mod) % mod;
 48             }
 49             ans.x[i][j] = tmp;
 50         }
 51     }
 52 
 53     return ans;
 54 }
 55 Matrix operator + (const Matrix& m1, const Matrix& m2) {
 56 
 57     Matrix ans;
 58     for (int i = 0; i < n; i++) {
 59         for (int j = 0; j < n; j++) {
 60             ans.x[i][j] = (m1.x[i][j] + m2.x[i][j]) % mod;
 61         }
 62     }
 63 
 64     return ans;
 65 }
 66 
 67 Matrix Quick_MatPow(Matrix m, int p) {
 68 
 69     Matrix ans;
 70     ans.unit();
 71     Matrix base = m;
 72     while (p) {
 73         if (p & 1) {
 74             ans = ans * base;
 75         }
 76         base = base * base;
 77         p >>= 1;
 78     }
 79 
 80     return ans;
 81 }
 82 
 83 Matrix a;
 84 
 85 int A[Maxn];
 86 Matrix Sum[Maxn << 2], lazy[Maxn << 2];
 87 
 88 //int fib[N << 2];
 89 //
 90 //ll tmp[2][2], res[2][2];
 91 //
 92 //void multi(ll a[][2], ll b[][2], int n)
 93 //{
 94 //    memset(tmp, 0, sizeof(tmp));
 95 //    for (ll i = 0; i < n; i++)
 96 //    {
 97 //        for (ll j = 0; j < n; j++)
 98 //        {
 99 //            for (ll k = 0; k < n; k++)
100 //            {
101 //                tmp[i][j] += (a[i][k] * b[k][j]) % mod;
102 //            }
103 //            tmp[i][j] = tmp[i][j] % mod;
104 //        }
105 //    }
106 //    for (ll i = 0; i < n; i++)
107 //        for (ll j = 0; j < n; j++)
108 //            a[i][j] = tmp[i][j];
109 //}
110 //
111 //void Pow(ll a[][2], ll m, int n)
112 //{
113 //    memset(res, 0, sizeof(res));//m是幂,n是矩阵大小
114 //    for (ll i = 0; i < n; i++) res[i][i] = 1;
115 //    while (m)
116 //    {
117 //        if (m & 1)
118 //            multi(res, a, n);//res=res*a;复制直接在multi里面实现了;
119 //        multi(a, a, n);//a=a*a
120 //        m >>= 1;
121 //    }
122 //}
123 
124 void PushUp(int rt) {
125     Sum[rt] = Sum[rt << 1] + Sum[rt << 1 | 1];
126     //FibSum[rt] = FibSum[rt << 1] + FibSum[rt << 1 | 1];
127 }
128 
129 void Build(int l, int r, int rt) {
130     //lazy[rt].unit();
131     if (l == r) {
132         //Sum[rt] = A[l];
133         Sum[rt] = Quick_MatPow(a, A[l]);
134         //cout << Sum[rt].x[1][0] << " ";
135         return;
136     }
137     int m = (l + r) >> 1;
138     Build(l, m, rt << 1);
139     Build(m + 1, r, rt << 1 | 1);
140     PushUp(rt);
141 }
142 
143 //void PointUpdate(int L, int C, int l, int r, int rt) {
144 //    if (l == r) {
145 //        //Sum[rt] = C;
146 //        return;
147 //    }
148 //    int m = (l + r) >> 1;
149 //    if (L <= m) PointUpdate(L, C, l, m, rt << 1);
150 //    else PointUpdate(L, C, m + 1, r, rt << 1 | 1);
151 //    PushUp(rt);
152 //}
153 
154 void PushDown(int rt, int ln, int rn) {
155     if (!lazy[rt].empty()) {
156         if (lazy[rt << 1].empty()) lazy[rt << 1] = lazy[rt];
157         else lazy[rt << 1] = lazy[rt << 1] * lazy[rt];
158         if(lazy[rt << 1 | 1].empty()) lazy[rt << 1 | 1] = lazy[rt];
159         else lazy[rt << 1 | 1] = lazy[rt << 1 | 1] * lazy[rt];
160         Sum[rt << 1] = Sum[rt << 1] * lazy[rt];
161         Sum[rt << 1 | 1] = Sum[rt << 1 | 1] * lazy[rt];
162         lazy[rt].clear();
163     }
164 }
165 
166 void QjUpdate(int L, int R, Matrix C, int l, int r, int rt) {
167     if (l >= L && r <= R) {
168         Sum[rt] = Sum[rt] * C;
169         //cout << "---------" << Sum[rt].x[1][0] << "\n";
170         if (lazy[rt].empty()) lazy[rt] = C;
171         else lazy[rt] = lazy[rt] * C;
172         return;
173     }
174     int m = (l + r) >> 1;
175     PushDown(rt, m - l + 1, r - m);
176     if (m >= L) QjUpdate(L, R, C, l, m, rt << 1);
177     if (m < R) QjUpdate(L, R, C, m + 1, r, rt << 1 | 1);
178     PushUp(rt);
179 }
180 
181 Matrix Query(int L, int R, int l, int r, int rt) {
182     if (l >= L && r <= R) {
183         return Sum[rt];
184     }
185     int m = (l + r) >> 1;
186     PushDown(rt, m - l + 1, r - m);
187     Matrix ANS;
188     ANS.clear();
189     if (m >= L) ANS = ANS + Query(L, R, l, m, rt << 1);
190     if (m < R) ANS = ANS + Query(L, R, m + 1, r, rt << 1 | 1);
191     return ANS;
192 }
193 
194 void print(int l, int r, int rt) {
195     if (l == r) {
196         cout << Sum[rt].x[1][0] << " ";
197         return;
198     }
199     int m = (l + r) >> 1;
200     PushDown(rt, m - l + 1, r - m);
201     print(l, m, rt << 1);
202     print(m + 1, r, rt << 1 | 1);
203     PushUp(rt);
204 }
205 
206 signed main() {
207 
208     ios::sync_with_stdio(false);
209     cin.tie(0);
210     int t, q;
211     //cin >> n;
212     a.init();
213     cin >> t >> q;
214     /*for (int i = 1; i <= 100; i++) {
215         cout << Quick_MatPow(a, i).x[1][0] << "\n";
216     }*/
217     for (int i = 1; i <= t; i++) {
218         cin >> A[i];
219     }
220     Build(1, t, 1);
221     //cout << "\n";
222     while (q--) {
223         int op;
224         cin >> op;
225         if (op == 1) {
226             int x, y, w;
227             cin >> x >> y >> w;
228             Matrix h = Quick_MatPow(a, w);
229             //cout << h.x[1][0] << "----\n";
230             QjUpdate(x, y, h, 1, t, 1);
231             //print(1, t, 1);
232             cout << "\n";
233         }
234         else {
235             int x, y;
236             cin >> x >> y;
237             cout << Query(x, y, 1, t, 1).x[1][0] << "\n";
238         }
239     }
240 
241     return 0;
242 }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值