基础题链接:https://blog.csdn.net/qq_48344603/article/details/107746383
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int MAXN = 1e5 + 5;
ll tree[MAXN * 4];
ll add[MAXN * 4];
ll num[MAXN];
int n, m;
void buildtree(int left,int right,int r) {
if (left == right) {
tree[r] = num[left];
return;
}
int mid = (left + right) / 2;
buildtree(left, mid, 2 * r);
buildtree(mid + 1,right, 2 * r + 1);
tree[r] = tree[2 * r] + tree[2 * r + 1];
}
void push_down(ll left,ll right, int u) {
ll len = right - left + 1;
tree[2 * u] += add[u] * (len - len / 2);
tree[2 * u + 1] += add[u] * (len / 2);
add[2 * u] += add[u];
add[2 * u + 1] += add[u];
add[u] = 0;
}
void update(ll l, ll r, ll tar, int left, int right, int u) {
if (left >= l && right <= r) {
tree[u] += tar * (right - left + 1);
add[u] += tar;
return;
}
if (add[u]) {
push_down(left, right, u);
}
int mid = (left + right) / 2;
if (l <= mid)update(l, r, tar, left, mid, 2 * u);
if (r > mid)update(l, r, tar, mid + 1, right, 2 * u + 1);
tree[u] = tree[2 * u] + tree[2 * u + 1];
}
ll query(ll l, ll r, int left, int right, int u) {
if (l <= left && r >= right) {
return tree[u];
}
if (add[u]) {
push_down(left, right, u);
}
int mid = (left + right) / 2;
ll sum = 0;
if (l <= mid)sum += query(l, r, left, mid, 2 * u);
if (r > mid)sum += query(l, r, mid + 1, right, 2 * u + 1);
return sum;
}
int main(){
ios::sync_with_stdio(false);
cin >> n >> m;
for (int i = 1;i <= n;i++) {
cin >> num[i];
}
buildtree(1, n, 1);
for (int i = 1;i <= m;i++) {
int c;
cin >> c;
if (c == 1) {
ll left, right, tar;
cin >> left >> right >> tar;
update(left, right, tar, 1, n, 1);
}
if (c == 2) {
ll left,right;
cin >> left >> right;
cout << query(left, right, 1, n, 1) << endl;
}
}
return 0;
}
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int MAXN = 1e5 + 5;
ll tree[MAXN * 4];
ll mul[MAXN * 4];
ll add[MAXN * 4];
ll num[MAXN];
int n, m, p;
//大部分都可以看题解
void push_down(int left, int right, int u) {
int len = right - left + 1;
tree[u << 1] = tree[u << 1] * mul[u] % p + add[u] * (len - len / 2);
tree[u << 1] %= p;
tree[u << 1 | 1] = tree[u << 1 | 1] * mul[u] % p + add[u] * (len / 2);
tree[u << 1 | 1] %= p;
mul[u << 1] *= mul[u], mul[u << 1] %= p;
mul[u << 1 | 1] *= mul[u], mul[u << 1 | 1] %= p;
//这部分做一些解释
//为何在左右子树的add里也要乘上mul,不是在mul操作时已经改了嘛?
//其实这2个操作不同,update2的操作只是对当前树的操作,而这里是对子树的操作,假设原来的子树就有add,现在我们从root往下down时,我们的mul只是把root的add操作了,并未对子树的add操作。
add[u << 1] = add[u << 1] * mul[u] + add[u];
add[u << 1 | 1] = add[u << 1 | 1] * mul[u] + add[u];
add[u << 1 | 1] %= p;
add[u << 1] %= p;
add[u] = 0;
mul[u] = 1;
}
void buildtree(int left, int right, int u) {
if (left == right) {
tree[u] = num[left];
return;
}
int mid=(left + right) / 2;
buildtree(left, mid, 2 * u);
buildtree(mid+1,right, 2 * u + 1);
tree[u] = (tree[2 * u] + tree[2 * u + 1]) %p;
}
void update1(ll l, ll r, ll tar, int left, int right, int u) {
if (l <= left && r >= right) {
tree[u] = (tree[u] + tar * (right - left + 1))%p;
add[u] += tar;
add[u] %= p;
return;
}
push_down(left, right, u);
int mid = (left + right) / 2;
if (l <= mid)update1(l,r, tar, left,mid, u<<1);
if (r > mid)update1(l,r, tar, mid+1,right, u << 1 | 1);
tree[u] = tree[u << 1] + tree[u << 1 | 1];
tree[u] %= p;
}
void update2(ll l, ll r, ll tar, int left, int right, int u) {
if (l <= left && r >= right) {
//这是乘法分配律
add[u] *= tar;
add[u] %= p;
tree[u] *= tar;
tree[u] %= p;
mul[u] *= tar;
mul[u] %= p;
return;
}
push_down(left, right, u);
int mid = (left + right) / 2;
if (l <= mid)update2(l, r, tar, left, mid, u << 1);
if (r > mid)update2(l, r, tar, mid + 1, right, u << 1 | 1);
tree[u] = tree[u << 1] + tree[u << 1 | 1];
tree[u] %= p;
}
ll query(ll l,ll r,int left, int right, int u) {
if (l <= left && r >= right) {
return tree[u];
}
push_down(left, right, u);
int mid = (left + right) / 2;
ll sum = 0;
if (l <= mid)sum = (sum + query(l, r, left, mid, u << 1))%p;
if (r > mid)sum = (sum + query(l, r, mid + 1, right, u << 1 | 1)) % p;
return sum;
}
int main() {
ios::sync_with_stdio(false);
cin >> n >> m >> p;
for (int i = 1;i <= 4 * n;i++)mul[i] = 1;
for (int i = 1;i <= n;i++) {
cin >> num[i];
num[i] %= p;
}
buildtree(1, n, 1);
for (int i = 1;i <= m;i++) {
int c;
cin >> c;
if (c == 1) {
ll l, r, tar;
cin >> l >> r >> tar;
update2(l, r, tar, 1, n, 1);
}
if (c == 2) {
ll l, r, tar;
cin >> l >> r >> tar;
update1(l, r, tar, 1, n, 1);
}
if (c == 3) {
ll l, r;
cin >> l >> r;
cout << query(l, r, 1, n, 1) << endl;
}
}
return 0;
}
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int MAXN = 1e5 + 5;
ll tree[MAXN * 4];
ll mul[MAXN * 4];
ll add[MAXN * 4];
ll num[MAXN];
int n, m, p;
//和2相同
void push_down(int left,int right,int u) {
int len = (right - left + 1);
tree[u << 1] = (tree[u << 1]*mul[u] + add[u] * (len-len/2)) % p;
tree[u << 1 | 1] = (tree[u << 1 | 1] * mul[u] + add[u] * (len / 2)) % p;
mul[u << 1] = (mul[u << 1] * mul[u]) % p;
mul[u << 1 | 1] = (mul[u << 1 | 1] * mul[u]) % p;
add[u << 1] = (add[u << 1] * mul[u] + add[u]) % p;
add[u << 1|1] = (add[u << 1|1] * mul[u] + add[u]) % p;
mul[u] = 1;
add[u] = 0;
}
void buildtree(int left, int right, int u) {
if (left == right) {
tree[u] = num[left];
return;
}
int mid = (left + right) >> 1;
buildtree(left, mid, u << 1);
buildtree(mid + 1, right, u << 1 | 1);
tree[u] = (tree[u << 1] + tree[u << 1 | 1])%p;
}
void update1(ll l, ll r,ll tar, int left, int right, int u) {
if (l <= left && r >= right) {
add[u] *= tar;
add[u] %= p;
tree[u] *= tar;
tree[u] %= p;
mul[u] *= tar;
mul[u] %= p;
return;
}
push_down(left,right,u);
int mid = (left + right)>>1;
if (l <= mid)update1(l, r, tar, left, mid, u << 1);
if (r > mid)update1(l, r, tar, mid + 1, right, u << 1 | 1);
tree[u] = (tree[u << 1] + tree[u << 1 | 1]) % p;
}
void update2(ll l, ll r, ll tar, int left, int right, int u) {
if (l <= left && r >= right) {
tree[u] += tar * (right - left + 1);
tree[u] %= p;
add[u] += tar;
add[u] %= p;
return;
}
push_down(left,right,u);
int mid = (left + right) >> 1;
if (l <= mid)update2(l, r, tar, left, mid, u << 1);
if (r > mid)update2(l, r, tar, mid + 1, right, u << 1 | 1);
tree[u] = (tree[u << 1] + tree[u << 1 | 1]) % p;
}
ll query(ll l, ll r, int left, int right, int u) {
if (l <= left && r >= right) {
return tree[u];
}
push_down(left, right, u);
int mid = (left + right) >> 1;
ll sum = 0;
if (l <= mid)sum =(sum+ query(l, r, left, mid, u << 1))%p;
if (r > mid)sum =(sum+ query(l, r, mid + 1, right, u << 1 | 1))%p;
return sum%p;
}
int main() {
std::ios::sync_with_stdio(false);
cin >> n >> p;
for (int i = 1;i <= 4 * n;i++)mul[i] = 1;
for (int i = 1;i <= n;i++) {
cin >> num[i];
num[i] %= p;
}
buildtree(1, n, 1);
cin >> m;
for (int i = 1;i <= m;i++) {
int c;
cin >> c;
if (c == 1) {
ll l, r, tar;
cin >> l >> r >> tar;
update1(l, r, tar, 1, n, 1);
}
if (c == 2) {
ll l, r, tar;
cin >> l >> r >> tar;
update2(l, r, tar, 1, n, 1);
}
if (c == 3) {
int l, r;
cin >> l >> r;
cout << query(l, r, 1, n, 1) << endl;
}
}
return 0;
}
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int MAXN = 1e4 + 5;
ll tree[MAXN * 4];
ll mul[MAXN * 4];
ll add[MAXN * 4];
ll num[MAXN];
int n, m;
int ans1=0, ans2=0;
//染色类线段树,注意区间时从0到n,而不是一般的从1到n
void update_cut(int l, int r, int left, int right, int rt) {
int mid = (left + right) / 2;
if (tree[rt] != 1 && tree[rt] != -1) {
//push_down
tree[rt << 1] = tree[rt << 1 | 1] = tree[rt];
}
if (l <= left && r >= right) {
if (tree[rt] == 0)return;//树为0表示子树都被砍了
else if (tree[rt] == 1) {
//为1就砍
tree[rt] = 0;
}
else if (tree[rt] == 2) {
//为2计算
ans1 += (right - left + 1);
ans2 = ans2 - (right - left + 1);
tree[rt] = 0;
}
else if (tree[rt] == -1) {
tree[rt] = 0;
if(l<=mid)update_cut(l, r, left, mid, rt<<1);
if (r > mid)update_cut(l, r, mid + 1, right, rt << 1 | 1);
}
}
else {
if (l <= mid)update_cut(l, r, left, mid, rt << 1);
if (r > mid)update_cut(l, r, mid + 1, right, rt << 1 | 1);
if (tree[rt << 1] == tree[rt << 1 | 1])tree[rt] = tree[rt << 1];
else tree[rt] = -1;
}
}
void update_plant(int l, int r, int left, int right, int rt) {
if (tree[rt] != 1 && tree[rt] != -1) {
tree[rt << 1] = tree[rt << 1 | 1] = tree[rt];
}
int mid = (left + right) >> 1;
if (l <= left && r >= right) {
if (tree[rt] == 1 || tree[rt] == 2)return;
if (tree[rt] == 0) {
tree[rt] = 2;
ans2 += right - left + 1;
}
if (tree[rt] == -1) {
//树也可能是1
if (l <= mid)update_plant(l, r, left, mid, rt << 1);
if (r > mid)update_plant(l, r, mid + 1, right, rt << 1 | 1);
if (tree[rt << 1] == tree[rt << 1 | 1]) {
tree[rt] = tree[rt << 1];
}
else tree[rt] = -1;
}
}
else {
if (l <= mid)update_plant(l, r, left, mid, rt << 1);
if (r > mid)update_plant(l, r, mid + 1, right, rt << 1 | 1);
if (tree[rt << 1] == tree[rt << 1 | 1]) {
tree[rt] = tree[rt << 1];
}
else tree[rt] = -1;
}
}
void swap(int l, int r) {
int tmp = l;
l = r;
r = tmp;
}
int main() {
std::ios::sync_with_stdio(false);
cin >> n >> m;
for (int i = 0;i <= 4 * n;i++)tree[i] = 1;
for (int i = 1;i <= m;i++) {
int c;
cin >> c;
if (c == 1) {
int l, r;
cin >> l >> r;
if (l > r)swap(l, r);
update_plant(l, r, 0, n, 1);
}
if (c == 0) {
int l, r;
cin >> l >> r;
if (l > r)swap(l, r);
update_cut(l, r, 0, n, 1);
}
}
cout << ans2 << endl;
cout << ans1 << endl;
return 0;
}
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int MAXN = 2e5 + 5;
ll tree[MAXN * 4];
ll mul[MAXN * 4];
ll add[MAXN * 4];
ll num[MAXN];
int p[MAXN];
int n, m;
//单点修改+区间查询模板
void buildtree(int left, int right, int rt) {
if (left == right) {
tree[rt] = num[left];
p[left] = rt;
return;
}
int mid = (left + right) >> 1;
buildtree(left, mid, rt << 1);
buildtree(mid + 1, right, rt << 1 | 1);
tree[rt] = max(tree[rt << 1], tree[rt << 1 | 1]);
}
void update(int pos, int tar, int left, int right, int rt) {
if (left == right) {
if (tree[rt] < tar) {
tree[rt] = tar;
}return;
}
int mid = (left + right) >> 1;
if (pos <= mid)update(pos, tar, left, mid, rt << 1);
else update(pos, tar, mid + 1, right, rt << 1 | 1);
tree[rt] = max(tree[rt << 1], tree[rt << 1 | 1]);
}
int query(int l, int r,int left,int right,int rt) {
if (l <= left && r >= right) {
return tree[rt];
}
int mid = (left + right) >> 1;
int maxn = 0;
if (l <= mid)maxn = max(maxn, query(l, r, left, mid, rt << 1));
if (r > mid)maxn = max(maxn, query(l, r, mid + 1, right, rt << 1 | 1));
return maxn;
}
int main() {
cin >> n >> m;
for (int i = 1;i <= n;i++) {
cin >> num[i];
}
buildtree(1, n, 1);
char ch;
for (int i = 1;i <= m;i++) {
cin >> ch;
if (ch == 'Q') {
int l, r;
cin >> l >> r;
cout << query(l, r, 1, n, 1) << endl;
}
if (ch == 'U') {
int l, r;
cin >> l >> r;
update(l, r, 1, n, 1);
}
}
return 0;
}
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int MAXN = 1e5 + 5;
ll tree[MAXN * 4] = {
0 };
ll mul[MAXN * 4];
ll add[MAXN * 4];
ll num[MAXN];
int p[MAXN];
int n, m;
void push_down(int rt) {
tree[rt << 1] ^= 1;
tree[rt << 1 | 1] ^= 1;
tree[rt] = 0;
return;
}
void update(int l, int r, int left, int right, int rt) {
if (l <= left && r >= right) {
tree[rt] ^= 1;
return;
}
if (tree[rt]) {
push_down(rt);
}
int mid = (left + right) >> 1;
if (l <= mid)update(l, r, left, mid, rt << 1);
if (r > mid)update(l, r, mid + 1, right, rt << 1 | 1);
}
int query(int pos, int left, int right, int rt) {
if (left == right)return tree[rt];
if (tree[rt]) {
push_down(rt);
}
int mid = (left + right) >> 1;
if (pos <= mid)return query(pos, left, mid, rt << 1);
else return query(pos, mid + 1, right, rt << 1 | 1);
}
int main() {
cin >> n >> m;
for (int i = 1;i <= m;i++) {
int c;
cin >> c;
if (c == 1) {
int l, r;
cin >> l >> r;
update(l, r, 1, n, 1);
}
if (c == 2) {
int pos;
cin >> pos;
cout<<query(pos, 1, n, 1)<<endl;
}
}
return 0;
}
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int MAXN = 1e5 + 5;
ll tree[MAXN * 4];
ll mul[MAXN * 4];
ll add[MAXN * 4];
ll num[MAXN];
int n, m;
int cnt = 0;
//可能是因为在线段树专题上,这题并没有那么难,但是这种题目很容易想到逆元
//对于线段树就是1和2的单点修改,1是乘上num[pos],2是化为1
void update(ll pos, int left, int right, int rt,int c) {
if (left == right) {
if (c == 1) {
tree[rt] *= num[pos];
tree[rt] %= m;
}
else {
tree[rt] =1;
}
return;
}
int mid = (left + right) >> 1;
if (pos <= mid)update(pos, left, mid, rt << 1,c);
else update(pos, mid + 1, right, rt << 1 | 1,c);
tree[rt] = (tree[rt << 1] * tree[rt << 1 | 1] % m);
}
int main() {
std::ios::sync_with_stdio(false);
int t;
cin >> t;
while (t--) {
cin >> n >> m;
memset(num, 0, sizeof num);
memset(tree, 0, sizeof tree);
cnt = 0;
for (int i = 1;i <= n * 4;i++)tree[i] = 1;
for (int i = 1;i <= n;i++) {
int c;
cin >> c;
if (c == 1) {
cin >> num[++cnt];
update(cnt, 1, n, 1, 1);
cout << tree[1] << endl;
}
if (c == 2) {
cin >> num[++cnt];
update(num[cnt], 1, n, 1, 2);
cout << tree[1] << endl;
}
}
}
return 0;
}
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int MAXN = 5e5 + 5;
ll tree[MAXN * 4];
ll mul[MAXN * 4];
ll add[MAXN * 4];
ll num[MAXN];
ll b[MAXN];
int n, m;
void update(ll pos, int left, int right, int rt) {
if (left == right) {
tree[rt] ++;
return;
}
int mid = (left + right) >> 1;
if (pos <= mid)update(pos, left, mid, rt << 1);
else update(pos, mid + 1, right, rt << 1 | 1);
tree[rt] = tree[rt << 1] + tree[rt << 1 | 1];
}
ll query(ll l, ll r, int left, int right, int rt) {
if (l <= left && r >= right) {
return tree[rt];
}
int mid = (left + right) >> 1;
ll sum = 0;
if (l <= mid)sum += query(l, r, left, mid, rt << 1);
if (r > mid)sum += query(l, r, mid + 1, right, rt << 1 | 1);
return sum;
}
int main() {
std::ios::sync_with_stdio(false);
cin >> n;
ll ans = 0;
for (int i = 1;i <= n;i++) {
cin >> num[i];
b[i] = num[i];
}
//下面4行是离散化,因为数据为1e9,我们直接开线段树肯定不行,所以离散化
sort(b + 1, b + 1 + n);//先对复制数组进行排序
int sz = unique(b + 1, b + 1 + n) - b-1;//unique函数是对相邻相同的值伪去除,实际上是把相同的放到数组末尾,所以数组大小并没有改变,并且unique返回的是“去除”后的数组的尾位置,所以我们减去b-1可以得到不重复数组的长度
for (int i = 1;i <= n;i++) {
//对原数组进行离散化
num[i] = lower_bound(b + 1, b + 1 + sz, num[i]) - b;//用lower_bound,在b数组中找到第一个小于等于num的数,为何减b,其实是减b+1,再+1,减去b+1得到第一个小于等于num数的位置,比如数组3 6 5 6 5 3 2 1,得到的值为2 4 3 4 3 2 1 0 所以我们+1,得到3 5 4 5 4 3 2 1
}
for (int i = n;i >= 1;i--) {
update(num[i], 1, n, 1);
if (num[i] == 1)continue;//1是最小的,防止下面num-1是的程序错误
ans += query(1, num[i] - 1, 1, n, 1);
}
cout << ans << endl;
return 0;
}
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int MAXN = 5e5 + 5;
ll tree[MAXN * 4];
ll mul[MAXN * 4];
ll add[MAXN * 4];
ll num[MAXN];
ll b[MAXN];
ll sm[MAXN];
ll bi[MAXN];
int n, m;
//2次逆序数,分别都是求一个数前面比他小的,和后面比他大的,因为数据为2的31次方,很大,所以我们离散化
void update(ll pos, int left, int right, int rt) {
if (left == right) {
tree[rt]++;
return;
}
int mid = (left + right) >> 1;
if (pos <= mid)update(pos, left, mid, rt << 1);
else update(pos, mid + 1, right, rt << 1 | 1);
tree[rt] = tree[rt << 1] + tree[rt << 1 | 1];
}
ll query(ll l, ll r, int left, int right, int rt) {
if (l <= left && r >= right) {
return tree[rt];
}
int mid = (left + right) >> 1;
ll sum = 0;
if (l <= mid)sum += query(l, r, left, mid, rt << 1);
if (r > mid)sum += query(l, r, mid + 1, right, rt << 1 | 1);
return sum;
}
int main() {
std::ios::sync_with_stdio(false);
cin >> n;
for (int i = 1;i <= n;i++) {
cin >> num[i];
b[i] = num[i];
}
sort(b + 1, b + 1 + n);
int sz = unique(b + 1, b + 1 + n) - b - 1;
for (int i = 1;i <= n;i++) {
num[i] = lower_bound(b + 1, b + 1 + sz, num[i]) - b;
}
for (int i = 1;i <= n;i++) {
if (num[i] == 1) {
update(num[i], 1, n, 1);
continue;
}
sm[i] = query(1, num[i] - 1, 1, n, 1);
update(num[i], 1, n, 1);
}
memset(tree, 0, sizeof tree);
for (int i = n;i >= 1;i--) {
if (num[i] == sz) {
update(num[i], 1, n, 1);
continue;
}
bi[i] = query(num[i] + 1, sz, 1, n, 1);
update(num[i], 1, n, 1);
}
ll ans = 0;
//cout << sz << endl;
for (int i = 1;i <= n;i++) {
//cout << i << " " <
ans += sm[i] * bi[i];
}
cout << ans << endl;
return 0;
}
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int MAXN = 2e5 + 5;
ll tree[MAXN * 4];
ll maxseg[MAXN * 4];
ll lmax[MAXN * 4], rmax[MAXN * 4];
bool L[MAXN * 4], R[MAXN * 4];
ll mul[MAXN * 4];
ll add[MAXN * 4];
ll num[MAXN];
ll len[MAXN * 4];
int n, m;
//这题也算经典类型的线段树,要维护多个区间值
void build(int left,int right,int rt) {
//主要为了得到每个区间的长度
len[rt] = right - left + 1;
if (left == right) {
return; }
int mid = (left + right) >> 1;
build(left, mid, rt << 1);
build(mid + 1, right, rt << 1 | 1);
}
void push_up(int left,int right,int rt) {
if (R[rt << 1] ^ L[rt << 1 | 1]) {
//如果左右子树的相接的点不同
maxseg[rt] = rmax[rt << 1] + lmax[rt << 1 | 1];//这里必须是赋值,不能改为max(maxseg,rmax+lmax),因为有时候update后,maxseg会减少,如果max的话,就不会了
maxseg[rt] = max(maxseg[rt], maxseg[rt << 1]);
maxseg[rt] = max(maxseg[rt], maxseg[rt << 1 | 1]);
}
else maxseg[rt] = max(maxseg[rt << 1], maxseg[rt << 1 | 1]);
if (lmax[rt << 1] ==len[rt<<1] && R[rt << 1] ^ L[rt << 1 | 1]) {
//更改包含左结点的最大长度
lmax[rt] = lmax[rt << 1] + lmax[rt << 1 | 1];
}
else {
lmax[rt] = lmax[rt << 1];
}
if (rmax[rt << 1 | 1] == len[rt << 1 | 1] && R[rt << 1] ^ L[rt << 1 | 1]) {
//包含右节点的最大长度
rmax[rt] = rmax[rt << 1 | 1] + rmax[rt << 1];
}
else rmax[rt] = rmax[rt << 1 | 1];
L[rt] = L[rt << 1];
R[rt] = R[rt << 1 | 1];//更新左右结点
}
void update(int pos, int left, int right, int rt) {
if (left == right) {
L[rt] = R[rt] = !L[rt];
return;
}
int mid = (left + right) >> 1;
if (pos <= mid)update(pos, left, mid, rt << 1);
else update(pos, mid + 1, right, rt << 1 | 1);
push_up(left,right,rt);
//cout << rt << " " << left << " " << right << " " << maxseg[rt] << endl;
}
int main() {
std::ios::sync_with_stdio(false);
cin >> n >> m;
build(1, n, 1);
for (int i = 1;i <= 4 * n;i++) {
maxseg[i] = 1;
L[i] = R[i] = 0;
lmax[i] = rmax[i] = 1;
}
for (int i = 1;i <= m;i++) {
int pos;
cin >> pos;
update(pos, 1, n, 1);
cout << maxseg[1] << endl;
}
return 0;
}
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int MAXN = 2e5 + 5;
ll tree[MAXN * 4];
ll maxseg[MAXN * 4];
ll lmax[MAXN * 4], rmax[MAXN * 4];
bool L[MAXN * 4], R[MAXN * 4];
ll mul[MAXN * 4];
ll lazy[MAXN * 4];
ll num[MAXN];
ll len[MAXN * 4];
int n, m;
//这题我们要维护子树包含左端点最大值,包含右端点最大值,区间最大值
void buildtree(int left, int right, int rt) {
len[rt]=maxseg[rt] = rmax[rt] = lmax[rt] = right - left + 1;
if (left == right)return;
int mid = (left + right) >> 1;
buildtree(left, mid, rt << 1);
buildtree(mid+1, right, rt << 1 | 1);
}
void push_up(int rt) {
//这里push_up用来更新rt结点
if (lmax[rt << 1] == len[rt << 1]) {
//下面3步为正常的区间维护最值
lmax[rt] = lmax[rt << 1] + lmax[rt << 1 | 1];
}
else lmax[rt] = lmax[rt << 1];
if (rmax[rt << 1 | 1] == len[rt << 1 | 1]) {
rmax[rt] = rmax[rt << 1 | 1] + rmax[rt << 1];
}
else rmax[rt] = rmax[rt << 1|1];
maxseg[rt] = max(max(rmax[rt << 1] + lmax[rt << 1 | 1], maxseg[rt << 1]), maxseg[rt << 1 | 1]);
}
void push_down(int rt) {
if (lazy[rt]) {
if (lazy[rt] == 1) {
maxseg[rt << 1] = maxseg[rt << 1 | 1] = 0;
rmax[rt << 1] = lmax[rt << 1] = rmax[rt << 1 | 1] = lmax[rt << 1 | 1] = 0;
lazy[rt << 1] = lazy[rt << 1 | 1] = 1;
}
else {
maxseg[rt << 1] = rmax[rt << 1] = lmax[rt << 1] = len[rt<<1];
maxseg[rt << 1 | 1] = lmax[rt << 1 | 1] = rmax[rt << 1 | 1] = len[rt << 1 | 1];
lazy[rt << 1] = lazy[rt << 1 | 1] = 2;
}
lazy[rt] = 0;
}
}
void update(int l, int r, int left, int right, int rt, int tag) {
int mid = (left + right) >> 1;
if (l <= left && r >= right) {
//正常区间修改,只是这里判断tag
if (tag == 1) {
maxseg[rt] = lmax[rt] = rmax[rt] = 0;
lazy[rt] = 1;
}
else {
maxseg[rt] = lmax[rt] = rmax[rt] = len[rt];
lazy[rt] = 2;
}
return;
}
push_down(rt);//如果不满足上面的if,我们就要进行拆开update,所以要push——down
if (l <= mid)update(l, r, left, mid, rt << 1, tag);
if (r > mid)update(l, r, mid + 1, right, rt << 1 | 1, tag);
push_up(rt);//对于2个子树我们update后,我们要对root结点进行改变
}
int query(int tar, int left, int right, int rt) {
push_down(rt);
if (left == right)return left;
int mid = (left + right) >> 1;
if (maxseg[rt << 1] >= tar)return query(tar, left, mid, rt << 1);
if (rmax[rt << 1] + lmax[rt << 1 | 1] >= tar)return mid - rmax[rt << 1] + 1;
else return query(tar, mid + 1, right, rt << 1 | 1);
}
int main() {
std::ios::sync_with_stdio(false);
cin >> n >> m;
buildtree(1, n, 1);
for (int i = 1;i <= m;i++) {
int c;
cin >> c;
if (c == 1) {
int tar;
cin >> tar;
if (maxseg[1] >= tar) {
int left = query(tar, 1, n, 1);
cout << left << endl;
update(left, left + tar-1, 1, n, 1, 1);
}
else cout << 0 << endl;
}
else {
int left, leng;
cin >> left >> leng;
update(left, left + leng - 1, 1, n, 1, 2);
}
//cout << rmax[2] << " " << lmax[3] << endl;
//cout << maxseg[3] << endl;
}
return 0;
}
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int MAXN = 2e5 + 5;
ll tree[MAXN * 4];
ll maxseg[MAXN * 4];
ll lmax[MAXN * 4], rmax[MAXN * 4];
bool L[MAXN * 4], R[MAXN * 4];
ll mul[MAXN * 4];
ll lazy[MAXN * 4];
ll num[MAXN];
ll len[MAXN * 4];
int n, m;
bool visit[MAXN];
//这题属于叠加类的线段树,有点染色类线段树的意思,但是不一样,染色类表示自己对这个区间就直接实现覆盖,并且可能覆盖多种颜色
//但是这题并不是,这题是叠加,同样地方完全可以埋无数颗地雷
//那么这区间查询地雷怎么做,假设我们update(a,b),其中b为update的右端点,a为左端点,那么我们a到b区间就有1颗地雷,以外区间没有,那么我们query区间(x,y),我们对于1到x-1找update中右端点共有几个,对于y+1到n找左端点有几个(我们将这些总和,这些地雷保证埋不到区间x到y)。每次埋雷用cnt++,最后我们用cnt减去不埋在x到y的地雷,就是埋在x到y的地雷数
void update(int pos, int tag, int left, int right, int rt) {
if (left == right) {
if (tag == 1)lmax[rt]++;
if (tag == 2)rmax[rt]++;
return;
}
int mid=(left + right) >> 1;
if (pos <= mid)update(pos, tag, left, mid, rt << 1);
else update(pos, tag, mid + 1,right, rt << 1 | 1);
if (tag == 1)lmax[rt] = lmax[rt << 1] + lmax[rt << 1 | 1];
else rmax[rt] = rmax[rt << 1] + rmax[rt << 1 | 1];
}
int query(int l, int r, int tag,int left, int right, int rt) {
if (l <= left && r >= right) {
if (tag == 1)return lmax[rt];
if (tag == 2)return rmax[rt];
}
int mid = (left + right) >> 1;
int sum = 0;
if (l <= mid)sum += query(l, r, tag, left, mid, rt << 1);
if (r > mid)sum += query(l, r, tag, mid + 1, right, rt << 1 | 1);
return sum;
}
int main() {
std::ios::sync_with_stdio(false);
cin >> n >> m;
int cnt = 0;
for (int i = 1;i <= m;i++) {
int c;
cin >> c;
if (c == 1) {
cnt++;
int l, r;
cin >> l >> r;
update(l, 1, 1, n, 1);
update(r, 2, 1, n, 1);
}
if (c == 2) {
int l, r;
cin >> l >> r;
int sum = 0;
if (l >= 2)sum+=query(1, l - 1, 2, 1, n, 1);
if (r <= n - 1)sum+=query(r + 1, n, 1, 1, n, 1);
cout << cnt - sum << endl;
}
}
return 0;
}
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int MAXN = 2e5 + 5;
ll tree[MAXN * 4];
ll maxseg[MAXN * 4];
ll lmax[MAXN * 4], rmax[MAXN * 4];
bool L[MAXN * 4], R[MAXN * 4];
ll mul[MAXN * 4];
ll lazy[MAXN * 4];
ll num[MAXN];
ll len[MAXN * 4];
int n, m;
bool visit[MAXN];
//一个区间加上等差数列,我们要想到差分,比如在l到r区间,我们用差分的话,在l到r区间加上等差数列,相当于在l加上K,在l+1到r加上D,在r+1处减去K+(l-r)*D
//我们用tree来维护差分值,num记录初始的数据
void push_down(int rt,int len) {
if (lazy[rt]) {
tree[rt << 1] += lazy[rt] * (len - len / 2);
tree[rt << 1 | 1] += lazy[rt] * (len / 2);
lazy[rt << 1] += lazy[rt];
lazy[rt << 1 | 1] += lazy[rt];
lazy[rt] = 0;
}
}
void updatelr(int l, int r, int D, int left, int right, int rt) {
if (l <= left && r >= right) {
tree[rt] += D * (right - left + 1);
lazy[rt] += D;
return;
}
push_down(rt, right - left + 1);
int mid = (left + right) >> 1;
if (l <= mid)updatelr(l, r, D, left, mid, rt << 1);
if (r > mid)updatelr(l, r, D, mid + 1, right, rt << 1 | 1);
tree[rt] = tree[rt << 1] + tree[rt << 1 | 1];
}
int query(int l,int r, int left, int right, int rt) {
if (l <= left && r >= right) {
return tree[rt];
}
push_down(rt, right - left + 1);
int mid = (left + right) >> 1;
int sum = 0;
if (l <= mid)sum += query(l, r, left, mid, rt << 1);
if (r > mid)sum += query(l, r, mid + 1, right, rt << 1 | 1);
return sum;
}
int main() {
std::ios::sync_with_stdio(false);
cin >> n >> m;
for (int i = 1;i <= n;i++) {
cin >> num[i];
}
for (int i = 1;i <= m;i++) {
int c;
cin >> c;
if (c == 1) {
int l, r, K, D;
cin >> l >> r >> K >> D;
updatelr(l,l, K, 1, n, 1);
if (r > l) {
updatelr(l + 1, r, D, 1, n, 1);//如果r==l的话我们我们这一步不用操作
}
if(r!=n)updatelr(r + 1,r+1, -(K+(r-l)*D), 1, n, 1);//如果r==n的话,就不用再r+1
}
if (c == 2) {
int r;
cin >> r;
cout << num[r]+query(1, r, 1, n, 1) << endl;
}
}
return 0;
}
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int MAXN = 2e5 + 5;
ll tree[MAXN * 4];
ll maxseg[MAXN * 4];
ll lmax[MAXN * 4], rmax[MAXN * 4];
bool L[MAXN * 4], R[MAXN * 4];
ll mul[MAXN * 4];
ll lazy[MAXN * 4];
ll num[MAXN];
ll len[MAXN * 4];
int n, m;
bool visit[MAXN];
//这题属于每个数的更新次数有限制,一个数最多更新6次,所以,假设最后把每个数都更新一遍需要6e5的复杂度,我们返回sum总和,维护sum,nlogm,为何是logm呢,我们暴力修改单点不应该是nm复杂度嘛,所以我们还要维护区间最大值,如果区间最大值>1,我们需要修改,其他我们不用,这样我们就省去多余步骤,复杂度降低。
void swap(int& l, int& r) {
int tmp = l;
l = r;
r = tmp;
}//防止l和r顺序不同
void buildtree(int left, int right, int rt) {
if (left == right) {
tree[rt] = num[left];
maxseg[rt] = num[left];
return;
}
int mid = (left + right) >> 1;
buildtree(left, mid, rt << 1);
buildtree(mid + 1, right, rt << 1 | 1);
tree[rt] = tree[rt << 1] + tree[rt << 1|1];
maxseg[rt] = max(maxseg[rt << 1], maxseg[rt << 1 | 1]);
}
void update(int l, int r, int left, int right, int rt) {
if (left == right) {
maxseg[rt] = tree[rt] = sqrt(maxseg[rt]);//单点暴力修改
return;
}
int mid = (left + right) >> 1;
if (l <= mid && maxseg[rt << 1] > 1)update(l, r, left, mid, rt << 1);
if (r > mid && maxseg[rt << 1 | 1] > 1)update(l, r, mid + 1, right, rt << 1 | 1);
maxseg[rt] = max(maxseg[rt << 1], maxseg[rt << 1 | 1]);
tree[rt] = tree[rt << 1] + tree[rt << 1 | 1];
}
ll query(int l, int r, int left, int right, int rt) {
if (l <= left && r >= right) {
return tree[rt];
}
int mid = (left + right) >> 1;
ll sum = 0;
if (l <= mid)sum += query(l, r, left, mid, rt << 1);
if (r > mid)sum += query(l, r, mid + 1, right, rt << 1 | 1);
return sum;
}
int main() {
std::ios::sync_with_stdio(false);
cin >> n;
for (int i = 1;i <= n;i++)cin >> num[i];
buildtree(1, n, 1);
cin >> m;
for (int i = 1;i <= m;i++) {
int c;
cin >> c;
if (c == 0) {
int l, r;
cin >> l >> r;
if (l > r)swap(l, r);
update(l, r, 1, n, 1);
}
if (c == 1) {
int l, r;
cin >> l >> r;
if (l > r) swap(l, r);
cout << query(l, r, 1, n, 1) << endl;
}
}
return 0;
}
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int MAXN = 2e5 + 5;
ll tree[MAXN << 2];
ll maxseg[MAXN * 4];
double cose[MAXN << 2], sine[MAXN << 2];
ll lazy[MAXN * 4];
ll num[MAXN];
ll len[MAXN * 4];
int n, m;
bool visit[MAXN];
//这题是卡常数的题目,所以建议用快读
int read() {
char c = getchar();int ans = 0;
while (c < '0' || c>'9') c = getchar();
while (c >= '0' && c <= '9') ans = (ans << 1) + (ans << 3) + (c ^ 48), c = getchar();
return ans;
}
//改变sin与cos,我们用到sin(a+x)=sina*cosx+cosa*sinx以及cos(a+x)=cosa*cosx-sina*sinx
void buildtree(int left, int right, int rt) {
if (left == right) {
sine[rt] = sin(num[left]);
cose[rt] = cos(num[left]);
return;
}
int mid = (left + right) >> 1;
buildtree(left, mid, rt << 1);
buildtree(mid + 1, right, rt << 1 | 1);
cose[rt] = cose[rt << 1] + cose[rt << 1 | 1];//这边用了乘法分配律,将拆开的sin与cos乘法分配
sine[rt] = sine[rt << 1] + sine[rt << 1 | 1];
}
void push_down(int rt) {
if (lazy[rt]) {
double s = sin(lazy[rt]), c = cos(lazy[rt]);
double s1 = sine[rt << 1], s2 = sine[rt << 1 | 1], c1 = cose[rt << 1], c2 = cose[rt << 1 | 1];//自己弄懂公式,这个也会懂
sine[rt << 1] = s1 * c + c1 * s;
sine[rt << 1 | 1] = s2 * c + c2 * s;
cose[rt << 1] = c1 * c - s1 * s;
cose[rt << 1 | 1] = c2 * c - s2 * s;
lazy[rt << 1] += lazy[rt];
lazy[rt << 1 | 1] += lazy[rt];
lazy[rt] = 0;
}
}
void update(int l, int r, int tar, int left, int right, int rt) {
if (l <= left && r >= right) {
double c = cose[rt], s = sine[rt];
sine[rt] = sin(tar) * c + cos(tar) * s;
cose[rt] = cos(tar) * c - sin(tar) * s;
lazy[rt] += tar;
return;
}
push_down(rt);
int mid = (left + right) >> 1;
if (l <= mid)update(l, r, tar,left, mid, rt << 1);
if (r > mid)update(l, r,tar, mid + 1, right, rt << 1 | 1);
sine[rt] = sine[rt << 1] + sine[rt << 1 | 1];//乘法分配
cose[rt] = cose[rt << 1] + cose[rt << 1 | 1];
}
double query(int l, int r, int left, int right, int rt) {
if (l <= left && r >= right) {
return sine[rt];
}
push_down(rt);
int mid = (left + right) >> 1;
double sum = 0;
if (l <= mid)sum += query(l, r, left, mid, rt << 1);
if (r > mid)sum += query(l, r, mid + 1, right, rt << 1 | 1);
return sum;
}
int main() {
n = read();
for (int i = 1;i <= n;i++)num[i] = read();
buildtree(1, n, 1);
m = read();
for (int i = 1;i <= m;i++) {
int c;
c = read();
if (c == 1) {
int l, r, tar;
l = read(), r = read(), tar = read();
update(l, r, tar, 1, n, 1);
}
if (c == 2) {
int l, r;
l = read(), r = read();
cout << fixed << setprecision(1) << query(l, r, 1, n, 1) << endl;
}
}
return 0;
}