zkw線段樹
目錄
例題 A Simple Problem with Integers HDU4267
例題 Can you answer these queries III HDU4027
A Simple Problem with Integers 代碼
Can you answer these queries III 代碼
基本知識
- 代碼短
- 常數小
- 空間小
1) 滿二叉樹,自底向上
zkw線段數是建立在滿二叉樹上,且只能自底向上操作。
2) 閉區間轉化成開區間 如:[2,6]->(1,7)
操作時需要將閉區間轉化爲開區間
const int M=1<<3;
L+=M-1,R+=M+1;3) 左指針爲左兒子,則包含右兒子
右指針爲右兒子,則包含左兒子
if(~L&1)ans+=T[L^1]; // ^爲取兄弟方法
if(R&1) ans+=T[R^1];4) 左右指針互爲兄弟爲結束條件
if(L^R^1)break;
單點修改+區間查詢
分析與代碼
單點修改,向上修改
向上尋找包含的兄弟
typedef long long LL;
const int maxn = 100005;
LL T[maxn << 1];
int M = 1 << 17;
void modify(int n, LL v) { //逐層向上,求和
for (T[n += M] = v, n >>= 1; n; n >>= 1)
T[n] = T[n << 1] + T[n << 1 | 1];
}
LL query(int l, int r) {
LL ans = 0; //逐層向上,取包含的區域
for (l += M - 1, r += M + 1; l ^ r ^ 1; l >>= 1, r >>= 1) {
if (~l & 1) ans += T[l ^ 1];
if (r & 1) ans += T[r ^ 1];
}
return ans;
}
例題 敵兵佈陣 HDU1166
Add i,j-> a[i]加j
Sub i,j->a[i]減j
query i,j->i到j求和
後附代碼
例題 I Hate It HDU1754
U i,j-> a[i]改爲j
Q i j->i到j求和
後附代碼
區間加減+單點查詢
分析與代碼
相當於lazy標記,記錄加減的數
單點向上尋找和加上記錄的標記
typedef long long LL;
const int maxn = 100005;
LL T[maxn << 1];
int M = 1 << 17;
void add(int l, int r) {
for (l += M - 1, r += M + 1; l ^ r ^ 1; l >>= 1, r >>= 1) {
if (~l & 1) T[l ^ 1] += v; //相當於lazy標記,記錄加減的數
if (r & 1) T[r ^ 1] += v;
}
}
LL query(int n){
LL ans = 0; //單點向上尋找和加上記錄的標記
for (n += M; n; n >>= 1)ans += T[n];
return ans;
}
例題 A Simple Problem with Integers HDU4267
從a到b,每隔k,加x 如 2,6,3,4表示2,5要加4
建立多顆線段樹,T【i】【j】【m】,包含所有mod(i)餘j的數
每次詢問一個點的值
區間最大子段和
分析與代碼
最大前綴 pre,最大後綴suf,最大子段和 max,區間和 sum
使用merge函數,實現合併操作
typedef long long LL;
struct Node {
LL pre, suf, max, sum;
}T[(M << 1) + 5],null;
Node merge(Node l, Node r) {
Node res;
res.sum = l.sum + r.sum;
res.pre = max(l.pre, l.sum + r.pre); //用右區間的前綴+左區間更新前綴
res.suf = max(r.suf, l.suf + r.sum); //用右區間+左區間的後綴更新後綴
res.max = max(max(l.max,r.max), l.suf + r.pre); //用左區間後綴+右區間前綴更新結果
return res;
}
void modify(int n, LL v) {
for (T[n += M] = { v,v,v,v }, n >>= 1; n; n >>= 1)
T[n] = merge(T[n << 1], T[n << 1 | 1]);
}
LL query(int l, int r) {
Node resL(null), resR(null);
for (l += M - 1, r += M + 1; l ^ r ^ 1; l >>= 1, r >>= 1) {
if (~l & 1) resL = merge(resL, T[l ^ 1]);
if (r & 1) resR = merge(T[r ^ 1], resR);
}
return merge(resL, resR).max;
}
例題 Can you answer these queries III HDU4027
單點修改+區間查詢
區間修改+區間最值
分析與代碼
void add(int L, int R, int v) {
L += M - 1, R += M + 1;
for (int l = L, r = R; l ^ r ^ 1; l >>= 1, r >>= 1) {
if (~l & 1)lazy[l ^ 1] += v, T[l ^ 1] += v; //既記錄加上後的數,又記錄標記
if (r & 1)lazy[r ^ 1] += v, T[r ^ 1] += v;
}
L >>= 1, R >>= 1;
for (int l = L, r = R; l; l >>= 1, r >>= 1) {
T[l] = max(T[l << 1], T[l << 1 | 1]) + lazy[l]; //加上上層標記
T[r] = max(T[r << 1], T[r << 1 | 1]) + lazy[r];
}
}
int query(int l, int r) {
int lMax = -inf, rMax = -inf;
for (l += M - 1, r += M + 1; l ^ r ^ 1; l >>= 1, r >>= 1) {
if (lazy[l] && lMax != -inf)lMax += lazy[l]; //再加標記
if (lazy[r] && rMax != -inf)rMax += lazy[r];
if (~l & 1)lMax = max(lMax, T[l ^ 1]); //先更新
if (r & 1)rMax = max(rMax, T[r ^ 1]);
}
for (; l; l >>= 1, r >>= 1)
lMax += lazy[l], rMax += lazy[r];
return max(lMax, rMax);
}
例題 Fast Arrangement HDU3577
板子題
區間覆蓋+區間求和
分析與代碼
區間覆蓋需要解決,無法區別標記的先後順序問題
若1-6標記x,4-8標記y,即無法辨認6的值應該爲x還是爲y
需要及時更新懶惰標記,避免矛盾
typedef long long LL;
const LL inf = 1e18;
const int M = 1 << 17;
LL T[M << 1], lazy[M << 1];
void modify(int L, int R, LL v) {
L += M - 1, R += M + 1; 更新懶惰標記,以區別標記的先後順序問題
for (int i = 20, l, r; i; --i) {
l = L >> i, r = R >> i;
if (lazy[l]) {
lazy[l << 1] = lazy[l << 1 | 1] = lazy[l];
T[l << 1] = T[l << 1 | 1] = lazy[l] * (1 << (i - 1));
lazy[l] = 0;
}
if (lazy[r]) {
lazy[r << 1] = lazy[r << 1 | 1] = lazy[r];
T[r << 1] = T[r << 1 | 1] = lazy[r] * (1 << (i - 1));
lazy[r] = 0;
}
}
for (int l = L, r = R, num = 1; l > 1; l >>= 1, r >>= 1, num <<= 1) {
if ((l ^ r ^ 1) > 1) {
if (~l & 1)lazy[l ^ 1] = v, T[l ^ 1] = v * num;
if (r & 1)lazy[r ^ 1] = v, T[r ^ 1] = v * num;
}
T[l >> 1] = T[l] + T[l ^ 1];
T[r >> 1] = T[r] + T[r ^ 1];
}
}
LL query(int l, int r) {
LL ansL = 0, ansR = 0, ln = 0, rn = 0, nn = 1;
for (l += M - 1, r += M + 1; l ^ r ^ 1; l >>= 1, r >>= 1,nn<<=1) {
if (lazy[l])ansL = lazy[l] * ln;
if (lazy[r])ansR = lazy[r] * rn;
if (~l & 1)ansL += T[l ^ 1], ln += nn;
if (r & 1)ansR += T[r ^ 1], rn += nn;
}
for (; l; l >>= 1, r >>= 1) {
if (lazy[l])ansL = lazy[l] * ln;
if (lazy[r])ansR = lazy[r] * rn;
}
return ansL + ansR;
}
例題 Just a Hook HDU1698
敵兵佈陣代碼
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;
#pragma warning (disable:4996)
typedef long long int LL;
const int M = 1 << 16;
LL T[M << 1];
void modify(int n, LL v) {
for (T[n += M] = v, n >>= 1; n; n >>= 1)
T[n] = T[n << 1] + T[n << 1 | 1];
}
LL query(int l, int r) {
LL ans = 0;
for (l += M - 1, r += M + 1; l ^ r ^ 1; l >>= 1, r >>= 1) {
if (~l & 1) ans += T[l ^ 1];
if (r & 1) ans += T[r ^ 1];
}
return ans;
}
int main() {
int t, g = 0;
scanf("%d", &t);
char s[10];
while (t--)
{
printf("Case %d:\n", ++g);
memset(T, 0, sizeof(T));
int n;
scanf("%d", &n);
LL v;
for (int i = 1; i <= n; i++)
scanf("%lld", &v), modify(i, v);
int i, j;
while (~scanf("%s",s))
{
if (s[0] == 'Q') {
scanf("%d%d", &i, &j);
printf("%lld\n", query(i, j));
}
else if (s[0] == 'A') {
scanf("%d%d", &i, &j);
modify(i, T[i + M] + j);
}
else if (s[0] == 'S') {
scanf("%d%d", &i, &j);
modify(i, T[i + M] - j);
}
else
break;
}
}
}
I Hate It 代碼
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
#pragma warning(disable:4996)
typedef long long LL;
const int M = 1 << 18;
int n, q;
LL a[M], T[M << 1];
void modify(int n, LL v) {
for (T[n += M] = v, n >>= 1; n; n >>= 1)
T[n] = max(T[n << 1], T[n << 1 | 1]);
}
LL query(int l, int r) {
LL ans = 0;
for (l += M - 1, r += M + 1; l ^ r ^ 1; l >>= 1, r >>= 1) {
if (~l & 1) ans = max(ans, T[l ^ 1]);
if (r & 1) ans = max(ans, T[r ^ 1]);
}
return ans;
}
int main() {
while (~scanf("%d%d", &n, &q)) {
memset(T, 0, sizeof(T));
for (int i = 1; i <= n; i++)
scanf("%lld", &a[i]);
for (int i = 1; i <= n; i++)
modify(i, a[i]);
char s[10];
while (q--)
{
scanf("%s", s);
int l, r;
if (s[0] == 'Q') {
scanf("%d%d", &l, &r);
printf("%lld\n", query(l, r));
}
else
{
scanf("%d%d", &l, &r);
modify(l, r);
}
/* for (int i = 1; i <= n; i++)
cout << T[M + i] << ' ';
cout << '\n';*/
}
}
}
A Simple Problem with Integers 代碼
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
#pragma warning (disable:4996)
const int M = 1 << 16;
int T[55][M << 1];
int a[M];
void add(int i,int l, int r, int v) {
for (l += M - 1, r += M + 1; l ^ r ^ 1; l >>= 1, r >>= 1) {
if (~l & 1) T[i][l ^ 1] += v;
if (r & 1) T[i][r ^ 1] += v;
}
}
int query(int i, int n) {
int ans = 0;
for (n += M; n; n >>= 1)ans += T[i][n];
return ans;
}
int main() {
int n;
int s[11] = { 0,0,1,3,6,10,15,21,28,36,45 };
while (~scanf("%d", &n))
{
for (int i = 1; i <= n; i++)
scanf("%d", &a[i]);
int q, g, x;
scanf("%d", &q);
while (q--)
{
scanf("%d", &g);
if (g == 2) {
scanf("%d", &x);
int ans = a[x];
for (int i = 1; i <= 10; i++)
ans += query(s[i] + x % i, x);
printf("%d\n", ans);
}
else {
int a, b, k, c;
scanf("%d%d%d%d", &a, &b, &k, &c);
add(s[k] + a % k, a, b, c);
}
}
memset(T, 0, sizeof(T));
}
}
Can you answer these queries III 代碼
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
#pragma warning(disable:4996)
typedef long long LL;
const int M = 1 << 16;
const int inf = 1e9;
int n, q;
LL a[M];
struct Node {
LL pre, suf, max, sum;
Node(){}
Node(LL a,LL b,LL c,LL d):pre(a),suf(b),max(c),sum(d){}
}T[(M << 1) + 5], null(-inf, -inf, -inf, -inf);
Node merge(Node l, Node r) {
Node res;
res.sum = l.sum + r.sum;
res.pre = max(l.pre, l.sum + r.pre);
res.suf = max(r.suf, l.suf + r.sum);
res.max = max(max(l.max,r.max), l.suf + r.pre);
return res;
}
void modify(int n, LL v) {
for (T[n += M] = Node( v,v,v,v ), n >>= 1; n; n >>= 1)
T[n] = merge(T[n << 1], T[n << 1 | 1]);
}
LL query(int l, int r) {
Node resL(null), resR(null);
for (l += M - 1, r += M + 1; l ^ r ^ 1; l >>= 1, r >>= 1) {
if (~l & 1) resL = merge(resL, T[l ^ 1]);
if (r & 1) resR = merge(T[r ^ 1], resR);
}
return merge(resL, resR).max;
}
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; i++)
scanf("%lld", &a[i]);
for (int i = 1; i <= n; i++)
modify(i, a[i]);
int s;
scanf("%d", &q);
while (q--)
{
scanf("%d", &s);
int l, r;
if (s == 1) {
scanf("%d%d", &l, &r);
printf("%lld\n", query(l, r));
}
else
{
scanf("%d%d", &l, &r);
modify(l, r);
}
}
}
Fast Arrangement 代碼
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cstring>
#include <vector>
using namespace std;
#pragma warning (disable:4996)
typedef long long LL;
const LL inf = 1e18;
const int M = 1 << 20;
LL T[M << 1], lazy[M << 1];
vector<int> E;
void add(int L, int R, LL v) {
L += M - 1, R += M + 1;
for (int l = L, r = R; l ^ r ^ 1; l >>= 1, r >>= 1) {
if (~l & 1)lazy[l ^ 1] += v, T[l ^ 1] += v;
if (r & 1)lazy[r ^ 1] += v, T[r ^ 1] += v;
}
L >>= 1, R >>= 1;
for (int l = L, r = R; l; l >>= 1, r >>= 1) {
T[l] = max(T[l << 1], T[l << 1 | 1]) + lazy[l];
T[r] = max(T[r << 1], T[r << 1 | 1]) + lazy[r];
}
}
LL query(int l, int r) {
LL lMax = -inf, rMax = -inf;
for (l += M - 1, r += M + 1; l ^ r ^ 1; l >>= 1, r >>= 1) {
if (lazy[l] && lMax != -inf)lMax += lazy[l];
if (lazy[r] && rMax != -inf)rMax += lazy[r];
if (~l & 1)lMax = max(lMax, T[l ^ 1]);
if (r & 1)rMax = max(rMax, T[r ^ 1]);
}
for (; l; l >>= 1, r >>= 1)
lMax += lazy[l], rMax += lazy[r];
return max(lMax, rMax);
}
int main() {
int t, g = 0;
scanf("%d", &t);
while (t--)
{
printf("Case %d:\n", ++g);
E.clear();
memset(T, 0, sizeof(T));
memset(lazy, 0, sizeof(lazy));
LL k, q;
scanf("%lld%lld", &k, &q);
LL l, r, v;
for (int i = 1; i <= q; i++)
{
scanf("%lld%lld", &l, &r);
if (query(l, r) < k) {
E.push_back(i);
add(l, r - 1, 1);
}
}
for (int i = 0; i < E.size() - 1; i++)
printf("%d ", E[i]);
printf("%d \n\n", E[E.size() - 1]);
}
}
Just a Hook代碼
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cstring>
#include <vector>
using namespace std;
#pragma warning (disable:4996)
typedef long long LL;
const LL inf = 1e18;
const int M = 1 << 20;
LL T[M << 1], lazy[M << 1];
vector<int> E;
void add(int L, int R, LL v) {
L += M - 1, R += M + 1;
for (int l = L, r = R; l ^ r ^ 1; l >>= 1, r >>= 1) {
if (~l & 1)lazy[l ^ 1] += v, T[l ^ 1] += v;
if (r & 1)lazy[r ^ 1] += v, T[r ^ 1] += v;
}
L >>= 1, R >>= 1;
for (int l = L, r = R; l; l >>= 1, r >>= 1) {
T[l] = max(T[l << 1], T[l << 1 | 1]) + lazy[l];
T[r] = max(T[r << 1], T[r << 1 | 1]) + lazy[r];
}
}
LL query(int l, int r) {
LL lMax = -inf, rMax = -inf;
for (l += M - 1, r += M + 1; l ^ r ^ 1; l >>= 1, r >>= 1) {
if (lazy[l] && lMax != -inf)lMax += lazy[l];
if (lazy[r] && rMax != -inf)rMax += lazy[r];
if (~l & 1)lMax = max(lMax, T[l ^ 1]);
if (r & 1)rMax = max(rMax, T[r ^ 1]);
}
for (; l; l >>= 1, r >>= 1)
lMax += lazy[l], rMax += lazy[r];
return max(lMax, rMax);
}
int main() {
int t, g = 0;
scanf("%d", &t);
while (t--)
{
printf("Case %d:\n", ++g);
E.clear();
memset(T, 0, sizeof(T));
memset(lazy, 0, sizeof(lazy));
LL k, q;
scanf("%lld%lld", &k, &q);
LL l, r, v;
for (int i = 1; i <= q; i++)
{
scanf("%lld%lld", &l, &r);
if (query(l, r) < k) {
E.push_back(i);
add(l, r - 1, 1);
}
}
for (int i = 0; i < E.size() - 1; i++)
printf("%d ", E[i]);
printf("%d \n\n", E[E.size() - 1]);
}
}