洛谷P3987 我永远喜欢珂朵莉~(set 树状数组)
题意
Sol
不会卡常,自愧不如。下面的代码只有66分。我实在懒得手写平衡树了。。
思路比较直观:拿个set维护每个数出现的位置,再写个线段树维护区间和
#include<bits/stdc++.h>
#define LL long long
const int MAXN = 5e5 + 10, INF = 1e9 + 7;
using namespace std;
template<typename A, typename B> inline bool chmax(A &x, B y) {
if(y > x) {x = y; return 1;}
else return 0;
}
template<typename A, typename B> inline bool chmin(A &x, B y) {
if(y < x) {x = y; return 1;}
else return 0;
}
inline int read() {
char c = getchar(); int x = 0, f = 1;
while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x * f;
}
int N, M, op[MAXN], ql[MAXN], qr[MAXN], val[MAXN];
LL a[MAXN];
bool ha[MAXN];
set<int> s[MAXN];
void gao(int pos, int x) {
for(int i = 1; i * i <= x; i++) {
if(x % i == 0) {
if(ha[i]) s[i].insert(pos);
if(i != (x / i))
if(ha[x / i]) s[x / i].insert(pos);
}
}
}
#define lb(x) (x & (-x))
LL T[MAXN];
void Add(int p, int v) {
while(p <= N) T[p] += v, p += lb(p);
}
LL Sum(int x) {
LL ans = 0;
while(x) ans += T[x], x -= lb(x);
return ans;
}
LL Query(int l, int r) {
return Sum(r) - Sum(l - 1);
}
void Modify(int p, int v) {
Add(p, -a[p]);
Add(p, a[p] / v);
}
void Change(int l, int r, int x) {
auto it = s[x].lower_bound(l);
while(1) {
int pos = *it;
if(it == s[x].end() || pos > r) return ;
if(a[pos] % x != 0) {it++; s[x].erase(prev(it)); continue;}
else Modify(pos, x), a[pos] /= x;
it++;
}
}
int main() {
// freopen("a.in", "r", stdin);
N = read(); M = read();
for(int i = 1; i <= N; i++) a[i] = read(), Add(i, a[i]);
for(int i = 1; i <= M; i++) {
op[i] = read(), ql[i] = read(); qr[i] = read();
if(op[i] == 1) val[i] = read(), ha[val[i]] = 1;
}
for(int i = 1; i <= N; i++) gao(i, a[i]);
for(int i = 1; i <= M; i++) {
if(op[i] == 1) {
if(val[i] != 1) Change(ql[i], qr[i], val[i]);
} else cout << Query(ql[i], qr[i]) << '\n';
}
return 0;
}
作者:自为风月马前卒
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。