建國中學 賴昭勳
懶標分成兩種:
seg[cur]代表當前節點經過子節點修改後的答案
該節點的懶標對seg[cur]做事,遇到的時候再處理。
這份講義會討論第二種
n,q≤2∗105
假設這兩個地方都有標記...
5
8
標記的先後會互相影響!
5
5
5
5, 5, 5, 5, 5...
X
4
seg[cur]紀錄的是「左右子節點更新完答案之後的結果」
合併時考慮左右節點與他們的懶標
2, 1, 4, 7
4, 4, 4, 4
相加
#include <iostream>
#include <algorithm>
#define maxn 100005
using namespace std;
int seg[4 * maxn], lazy[4 * maxn];
void modify(....) {
if (r <= l || ql >= r || qr <= l) return;
if (ql <= l && qr >= r) {
PUT_TAG;
return;
}
int mid = (l + r) / 2;
modify(LEFT_CHILD);
modify(RIGHT_CHILD);
PULL seg[cur];
}
應該在哪裡加上push操作?
PUSH(cur);
PUSH(LEFT);
PUSH(RIGHT);
#include <iostream>
#include <algorithm>
#define maxn 100005
using namespace std;
int seg[4 * maxn], lazy[4 * maxn];
void modify(....) {
if (r <= l || ql >= r || qr <= l) return;
if (ql <= l && qr >= r) {
PUT_TAG;
return;
}
int mid = (l + r) / 2;
modify(LEFT_CHILD);
modify(RIGHT_CHILD);
PULL seg[cur];
}
應該在哪裡加上push操作?
PUSH(cur);
PUSH(LEFT);
PUSH(RIGHT);
int query(....) {
if (r <= l || ql >= r || qr <= l) return 0;
if (ql <= l && qr >= r) {
return seg[cur];
}
int mid = (l + r) / 2;
return COMBINE(query(LEFT) + query(RIGHT));
}
push(cur);
應該在哪裡加上push操作?
int query(....) {
if (r <= l || ql >= r || qr <= l) return 0;
if (ql <= l && qr >= r) {
return seg[cur];
}
int mid = (l + r) / 2;
return COMBINE(query(LEFT) + query(RIGHT));
}
push(cur);
應該在哪裡加上push操作?
修改,詢問皆為O(logn)
void push(int cur, int l, int r) { //[l, r)
seg[cur] = (r - l) * tag[cur];
if (r - l > 1) {
tag[cur * 2] = tag[cur];
tag[cur * 2 + 1] = tag[cur];
}
tag[cur] = 0;
}
但是在push裡面要怎麼寫...
如果在同一個區間,我之前有加值的標記,現在新增一個改值操作,那改值操作會把加值覆蓋掉
因此,實作的時候要保證:如果一個節點同時有加值和改值標記,那一定代表是先改值後加值。
寫push 的時候:
給你一個正整數序列A,支援兩種操作
1. 把區間[l,r]的數字ai全部改成min(ai,x)
2. 把區間[l,r]的數字ai全部改成max(ai,x)
最後請輸出整個序列
n≤2×106,q≤5×105
1. 單點修改某個元素的值
2. 詢問區間[l,r]的最大連續和
有三種可能:
對於每個區間,我們需要知道:
答案會是:max(left.all,right.all,left.suf+right.pref)
1. 把[l,r]的值加上k
2. 詢問區間[l,r]的最大公因數
n,q≤105
1. 把ai加上k
2. 詢問整個序列,選取任意多個互不相鄰元素的最大和
n≤40000, q≤50000
給你一個序列,支援兩種操作:
1. 單點改值
2. 詢問總和≤x的最長前綴長度(aka對前綴取lower_bound)
n,q≤5×105,ai≥0
總複雜度:O(n+qlog2n)
可不可以更好?
Query: 30
Sum: 13
Query: 17
Sum: 20
n≤8×105
大致想法:把資料的兩個維度畫在空間平面上。枚舉一個維度,並用線段樹解決掉另一個維度。
不管是原本的資料,修改,或是詢問都可以對應到空間上的點、線、或平面!
也就是說,往往是離線處理詢問
給你一個兩個1~n的排列a,b,有q筆詢問。每次詢問a[l1...r1]和b[l2...r2]的組成元素是否相同
n,q≤105
給你一個序列,支援兩種操作:
1. 單點改值
2. 給你一個x,詢問max(ai⊕x)
n,q≤2×105,0≤ai≤109
祝各位魔境加油 ;P