题目来源
https://codeforces.ml/gym/102798
题意分析
题目意思的大致可以描述为,给一个长度为n的序列,有两次操作。操作1是将某一区间段的数全部加1,操作2是询问以某两个位置x,y为起点的长度为ln的序列是否相同,进行yes\no的输出。需要注意的是,区间中的所有数字都在[0,65535)这个区间之内。
思路分析
由操作1想到的是线段树。由操作2想到的是hash。用线段树维护区间的最大值,哈希值和哈希基数值。然后对于操作1来说,就是一个区间修改+区间判断修改(即判断是否出现越界情况)。操作2就是一个区间查询。
说的很容易,然而还是被这道题上了一课。
code
1 #include <bits/stdc++.h>
2
3 #define int long long
4 using namespace std;
5 const int maxn = 5e5 + 7;
6 const int pp = 13331;
7 const int mod = 1e9 + 7;
8 const int MOD = 65536;
9
10 int a[maxn];
11 int tree[maxn << 2], ver[maxn << 2], lz[maxn << 2];
12 int base[maxn << 2], ps[maxn << 2];
13
14 void init(){
15 base[0] = 1;
16 for (int i=1; i<maxn; i++) base[i] = base[i-1] * pp % mod;
17 }
18
19 void pushdown(int p){
20 if (lz[p]){
21 lz[p << 1] += lz[p];
22 lz[p << 1 | 1] += lz[p];
23 ver[p << 1] = (ver[p << 1] + ps[p << 1] * lz[p]) % mod;
24 ver[p << 1 | 1] = (ver[p << 1 | 1] + ps[p << 1 | 1] * lz[p]) % mod;
25 tree[p << 1] += lz[p];
26 tree[p << 1 | 1] += lz[p];
27 lz[p] = 0;
28 }
29 }
30
31 void build(int p, int l, int r){
32 if (l == r){
33 tree[p] = a[l]; ver[p] = (base[l] * a[l]) % mod; ps[p] = base[l];
34 // cout << "P: " << p << " " << tree[p] << " " << ver[p] << " " << ps[p] << endl;
35 return;
36 }
37 int mid = l + r >> 1;
38 build(p << 1, l, mid);
39 build(p << 1 | 1, mid + 1, r);
40 tree[p] = max(tree[p << 1], tree[p << 1 | 1]);
41 ps[p] = (ps[p << 1] + ps[p << 1 | 1]) % mod;
42 ver[p] = (ver[p << 1] + ver[p << 1 | 1]) % mod;
43 // cout << "P: " << p << " " << tree[p] << " " << ver[p] << " " << ps[p] << endl;
44 }
45
46 void update(int p, int l, int r, int L, int R, int x){
47 if (L <= l && r <= R){
48 lz[p] += x; tree[p] += x; ver[p] = (ver[p] + ps[p]) % mod;
49 return;
50 }
51
52 int mid = l + r >> 1;
53 pushdown(p);
54 if (L <= mid) update(p << 1, l, mid, L, R, x);
55 if (mid < R) update(p << 1 | 1, mid + 1, r, L, R, x);
56 tree[p] = max(tree[p << 1], tree[p << 1 | 1]);
57 ver[p] = (ver[p << 1] + ver[p << 1 | 1]) % mod;
58 }
59
60 void umod(int p, int l, int r){
61 // cout << p << " " << tree[p] << " " << l << " " << r << " %%%%\n";
62 if (tree[p] < MOD) return;
63 if (l == r){
64 tree[p] = 0;
65 ver[p] = 0; lz[p] = 0;
66 return;
67 }
68 pushdown(p);
69 int mid = l + r >> 1;
70 umod(p << 1, l, mid);
71 umod(p << 1 | 1, mid + 1, r);
72 tree[p] = max(tree[p << 1], tree[p << 1 | 1]);
73 ver[p] = (ver[p << 1] + ver[p << 1 | 1]) % mod;
74 }
75
76 int ask(int p, int l, int r, int L, int R){
77 if (L <= l && r <= R) {
78 // cout << "p" << p <<endl;
79 return ver[p];
80 }
81 int mid = l + r >> 1;
82 pushdown(p);
83 int ans = 0;
84 if (L <= mid) ans += ask(p << 1, l, mid, L, R);
85 ans %= mod;
86 if (mid < R) ans += ask(p << 1 | 1, mid + 1, r, L, R);
87 ans %= mod;
88 return ans;
89 }
90
91 signed main(){
92 init();
93 int n, q; scanf("%lld%lld", &n, &q);
94 for (int i=1; i<=n; i++) scanf("%lld", &a[i]);
95 build(1, 1, n);
96
97
98
99 while (q --){
100 int op; scanf("%lld", &op);
101 if (op == 1){
102 int l, r; scanf("%lld%lld", &l, &r);
103 update(1, 1, n, l, r, 1);
104 umod(1, 1, n);
105
106 // cout << ask(1, 1, n, 1, 1) << " " << ask(1, 1, n, 2, 2) << " " << ask(1, 1, n, 3, 3) << endl;
107
108 }else {
109 int x, y, ln;
110 scanf("%lld%lld%lld", &x, &y, &ln);
111 if (x > y) swap(x, y);
112 int ans1 = ask(1, 1, n, x, x + ln - 1);
113 // cout << "&&&&&&" << endl;
114 // cout << x << " " << x+ln << endl;
115 int ans2 = ask(1, 1, n, y, y + ln - 1);
116 // cout << "ans1: " << ans1 << endl;
117 ans1 = ans1 * base[y-x] % mod;
118 // cout << "ans1: " << ans1 << " ans2: " << ans2 << endl;
119 if (ans1 == ans2) printf("yes\n");
120 else printf("no\n");
121 }
122 }
123 return 0;
124 }
125 /*
126 5 1
127 1 2 1 2 1
128 2 1 3 3
129
130 3 2
131 0 65535 65535
132 1 2 3
133 2 1 2 2
134 */