[kuangbin]
專題7 線段樹 題解 + 總結
kuangbin帶你飛
:點擊進入新世界
kuangbin
專題十二 基礎DP1 題解+總結:https://www.cnblogs.com/RioTian/p/13110438.html
kuangbin
專題六 最小生成樹 題解+總結:https://www.cnblogs.com/RioTian/p/13380764.html
[kuangbin]
專題九 連通圖 題解+總結 : https://www.cnblogs.com/RioTian/p/13395039.html
因為專題是后面制作,所以可能部分題目題解會需要轉去我的另一篇題解記錄上
總結:
待補。。。
1. 敵兵布陣
思路:
基礎模板題
三種思路:維護一個前綴數組,但容易超時、樹狀數組、線段樹
2. I Hate It
題意理解很簡單,這里就說下注意點,數組要開大點不然容易RE,同時因為數據較大,可以采用快讀或者scanf
#include<bits/stdc++.h>
using namespace std;
#define ms(x, n) memset(x,n,sizeof(x));
typedef long long LL;
const int inf = 1<<30;
const LL maxn = 200000+5;
int N, M, a[maxn];
int maxA[maxn*4];
void pushup(int id){maxA[id] = max(maxA[id<<1], maxA[id<<1|1]);}
void build(int id, int l, int r){
if(l==r){
maxA[id] = a[l];
return;
}
int mid = (l+r)>>1;
build(id<<1, l, mid);
build(id<<1|1, mid+1, r);
pushup(id);
}
void update(int id, int l, int r, int x, int v){
if(l==r){
maxA[id] = v;
return;
}
int mid = (l+r)>>1;
if(x<=mid) update(id<<1, l, mid, x, v);
else update(id<<1|1, mid+1, r, x, v);
pushup(id);
}
int query(int id, int l, int r, int x, int y){
if(x<=l && y>=r) return maxA[id];
int mid = (l+r)>>1, ret = -inf;
if(x <= mid) ret = max(ret, query(id<<1, l, mid, x, y));
if(y > mid) ret = max(ret, query(id<<1|1, mid+1, r, x, y));
return ret;
}
int main()
{
char opt;
int x, y;
while(scanf("%d%d",&N,&M)!=EOF){
ms(a, 0);
fill(maxA, maxA+maxn, -inf);
for(int i = 1; i <= N; i++)
scanf("%d",&a[i]);
build(1, 1, N);
while(M--){
scanf(" %c%d%d",&opt,&x,&y);
if(opt=='Q')
printf("%d\n",query(1, 1, N, x, y));
else if(opt=='U')
update(1, 1, N, x, y);
}
}
return 0;
}
樹狀數組
#include<bits/stdc++.h>
using namespace std;
#define sc(n) scanf("%c",&n)
#define sd(n) scanf("%d",&n)
#define pd(n) printf("%d\n", (n))
#define sdd(n,m) scanf("%d %d",&n,&m)
#define sddd(n,m,z) scanf("%d %d %d",&n,&m,&z)
#define pdd(n,m) printf("%d %d\n",n, m)
#define ms(a,b) memset(a,b,sizeof(a))
#define mod(x) ((x)%MOD)
#define lowbit(x) (x & (-x))
typedef long long ll;
typedef pair<int, int> PII;
typedef vector<int> VI;
typedef vector<string> VS;
const int MOD = 10000007;
const int inf = 0x3f3f3f3f;
const int maxn = 2e5 + 100;
int n, m, s;
int c[maxn], d[maxn];//另開一個數組維護原始成績值,利用它更新max
void update(int x){
while (x <= n){
d[x] = c[x];
int lx = lowbit(x);
for (int i = 1; i < lx; i <<= 1)//這里是注意點
d[x] = max(d[x], d[x - i]);
x += lowbit(x);
}
}
int getmax(int l, int r) {
int ans = 0;
while (r >= l) {
ans = max(ans, c[r--]);
while (r - lowbit(r) >= l) {
ans = max(ans, d[r]);
r -= lowbit(r);
}
}
return ans;
}
int main() {
//freopen("in.txt", "r", stdin);
//ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
while (sdd(n,m) != EOF) {
ms(d, 0);
for (int i = 1; i <= n; ++i) {
sd(c[i]);
update(i);
}
char opt; int a, b;
while (m--) {
getchar();//清除回車
sc(opt), sdd(a, b);
if (opt == 'U')
c[a] = b, update(a);
else
printf("%d\n", getmax(a, b));
}
}
return 0;
}
3.A Simple Problem with Integers
思路:模板題,別敲錯板子就行(WA好幾次2333)
#include <stdio.h>
using namespace std;
typedef long long ll;
const ll inf = 4e18+10;
const int mod = 1000000007;
const int mx = 5e6+5;
ll sum[mx], add[mx];
void pushup(int rt) {
sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];
}
void pushdown(int rt, int m) {//更新rt的子節點
if (add[rt]) {
add[rt << 1] += add[rt];
add[rt << 1 | 1] += add[rt];
sum[rt << 1] += (m - (m >> 1))* add[rt];
sum[rt << 1 | 1] += (m >> 1)* add[rt];
add[rt] = 0;//取消本層標記
}
}
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
void biuld(int l, int r, int rt) {//用滿二叉樹建樹
add[rt] = 0;
if (l == r) {//葉子結點,賦值
scanf("%lld", &sum[rt]);
return;
}
int mid = (l + r) >> 1;
biuld(lson);
biuld(rson);
pushup(rt);//向上更新區間和
}
void update(int a, int b, ll c, int l, int r, int rt) {//區間更新
if (a <= l && b >= r) {
sum[rt] += (r - l + 1) * c;
add[rt] += c;
return;
}
pushdown(rt, r - l + 1);//向下更新
int mid = (l + r) >> 1;
if (a <= mid)update(a, b, c, lson);//分成兩半深入
if (b > mid)update(a, b, c, rson);
pushup(rt);
}
ll query(int a, int b, int l, int r, int rt) {//區間求和
if (a <= l && b >= r)
return sum[rt];//滿足lazy直接返回
pushdown(rt, r - l + 1);
int mid = (l + r) >> 1;
ll ans = 0;
if (a <= mid)ans += query(a, b, lson);
if (b > mid)ans += query(a, b, rson);
return ans;
}
int main()
{
//ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int n, m;
scanf("%d", &n); scanf("%d", &m);
biuld(1, n, 1);
while (m--) {
char str[2];
int a, b;
ll c;
scanf("%s", str);
if (str[0] == 'C') {
scanf("%d", &a); scanf("%d", &b); scanf("%lld", &c);
update(a, b, c, 1, n, 1);
}
else {
scanf("%d", &a); scanf("%d", &b);
printf("%lld\n", query(a, b, 1, n, 1));
}
}
return 0;
}
4.Mayor's posters
線段樹 + 離散化
https://www.cnblogs.com/RioTian/p/13410156.html
5. Just a Hook
題意:
N個數, 初始全部為1, 進行Q次以下操作
把[l, r]的所有值改為V (1<=V<=3)
求N個數的和.
題解:
套上線段樹區間更新的板子, 把求和的+= 改為 =
#include<bits/stdc++.h>
using namespace std;
#define sc(n) scanf("%c",&n)
#define sd(n) scanf("%d",&n)
#define pd(n) printf("%d\n", (n))
#define sdd(n,m) scanf("%d %d",&n,&m)
#define sddd(n,m,z) scanf("%d %d %d",&n,&m,&z)
#define pdd(n,m) printf("%d %d\n",n, m)
#define ms(a,b) memset(a,b,sizeof(a))
#define all(c) c.begin(),c.end()
#define pb push_back
#define fi first
#define se second
#define mod(x) ((x)%MOD)
#define lowbit(x) (x & (-x))
#define gcd(a,b) __gcd(a,b)
typedef long long ll;
typedef pair<int, int> PII;
typedef vector<int> VI;
typedef vector<string> VS;
const int MOD = 1e9 + 7;
const double eps = 1e-9;
const int inf = 0x3f3f3f3f;
const int maxn = 1e5 + 5;
int t, n, m, x, y, z, sum[maxn << 2], ans;
void pushdown(int p) {
if (sum[p] == -1)return;
sum[p << 1] = sum[p << 1 | 1] = sum[p];
sum[p] = -1;
}
void update(int id, int l, int r, int x, int y, int z) {
if (x <= l && r <= y) {
sum[id] = z; return;
}
pushdown(id);
int m = (l + r) >> 1;
if (x <= m)update(id << 1, l, m, x, y, z);
if (y > m) update(id << 1 | 1, m + 1, r, x, y, z);
}
void query(int id, int l, int r) {
if (sum[id] != -1) {
ans += sum[id] * (r - l + 1);
return;
}
int mid = (l + r) >> 1;
query(id << 1, l, mid);
query(id << 1 | 1, mid + 1, r);
}
int main() {
//freopen("in.txt", "r", stdin);
//ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int Kcase = 1;
sd(t); while (t--) {
ans = 0; ms(sum, -1);
sdd(n, m); sum[1] = 1;
while (m--) {
sddd(x, y, z);
update(1, 1, n, x, y, z);
}
query(1, 1, n);
printf("Case %d: The total value of the hook is %d.\n", Kcase++, ans);
}
return 0;
}
6.Count the Colors
題解: https://www.cnblogs.com/RioTian/p/13410855.html
7. Balanced Lineup
線段樹 搭配注釋理解
#include <iostream>
#include <cstdio>
using namespace std;
typedef pair<int, int > PII;
const int N = 50000 + 10, M = N * 4;
struct Node {
// 不用開long long
int l, r, hei, low;
} root[M];
void pushup(int now) {
// 記錄最高的和最矮的牛的高度
root[now].hei = max(root[now << 1].hei, root[now << 1 | 1].hei);
root[now].low = min(root[now << 1].low, root[now << 1 | 1].low);
}
void build(int now, int left, int right) {
root[now].l = left, root[now].r = right;
if (left == right) {
// 直接輸入葉子節點的值,很方便,而且省空間
scanf("%d", &root[now].hei);
// 默認葉子節點的牛既是最高的,也是最矮的
root[now].low = root[now].hei;
return;
}
int mid = (left + right) >> 1;
int ln = now << 1, rn = now << 1 | 1;
build(ln, left, mid);
build(rn, mid + 1, right);
pushup(now);
}
// 甚至不用寫update和pushdown...
PII query(int now, int L, int R) {
// 找到了要的區間返回這個區間的最大值和最小值,用來和后面的區間進行對比
if (L <= root[now].l && root[now].r <= R) return PII(root[now].hei, root[now].low);
// 規定first為最大值,second為最小值,那么沒找到就返回一個極端值就行了
if (L > root[now].r || R < root[now].l) return PII(-1e9, 1e9);
// 不用pushdown
// 找到左右子樹的最大值和最小值對,然后對比
PII nhei = query(now << 1, L, R);
PII nlow = query(now << 1 | 1, L ,R);
// 對比左區間的最大值和右區間的最大值,左區間的最小值和右區間的最小值...
return PII(max(nhei.first, nlow.first), min(nhei.second, nlow.second));
}
int main() {
int n, m, l ,r;
scanf("%d%d", &n, &m);
build(1, 1, n);
while (m--) {
scanf("%d%d", &l, &r);
PII res = query(1, l, r);
printf("%d\n", res.first - res.second);
}
return 0;
}
樹狀數組
//選C++ 而不是G++
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define mod 1000000007
#define INF 0x3f3f3f3f
#define MAX 50005
int Max[MAX], Min[MAX];
int a[MAX];
int n, q;
inline void read(int& x) {
char ch;
bool flag = false;
for (ch = getchar(); !isdigit(ch); ch = getchar())if (ch == '-') flag = true;
for (x = 0; isdigit(ch); x = x * 10 + ch - '0', ch = getchar());
x = flag ? -x : x;
}
inline void write(int x) {
static const int maxlen = 100;
static char s[maxlen];
if (x < 0) { putchar('-'); x = -x; }
if (!x) { putchar('0'); return; }
int len = 0; for (; x; x /= 10) s[len++] = x % 10 + '0';
for (int i = len - 1; i >= 0; --i) putchar(s[i]);
}
int lowbit(int x){
return x & -x;
}
void updata(int i, int val){
while (i <= n){
Min[i] = min(Min[i], val);
Max[i] = max(Max[i], val);
i += lowbit(i);
}
}
int query(int l, int r)
{
int maxn = a[l], minn = a[r];
while (1) {
maxn = max(maxn, a[r]), minn = min(minn, a[r]);
if (l == r) break;
for (r -= 1; r - l >= lowbit(r); r -= lowbit(r))
maxn = max(Max[r], maxn), minn = min(minn, Min[r]);
}
return maxn - minn;
}
int main(){
memset(Min, INF, sizeof(Min));
read(n); read(q);
for (int i = 1; i <= n; i++) {
read(a[i]);
updata(i, a[i]);
}
while (q--){
int a, b;
read(a), read(b);
write(query(a, b));
putchar('\n');
}
return 0;
}
8. Can you answer these queries?
線段樹,保留有用的功能即可。
#include<bits/stdc++.h>
typedef long long ll;
#define mid (l+r)/2
#define lch in*2
#define rch in*2+1
const int maxn = 1e5 + 9;
int N, M, L, R;
ll tr[maxn * 4] = {};
void build(int in = 1, int l = 1, int r = N) {
if (l == r) return void(scanf("%lld", tr + in));
build(lch, l, mid); build(rch, mid + 1, r);
tr[in] = tr[lch] + tr[rch];
}
void update(int in = 1, int l = 1, int r = N) {
if (l > R || r < L || tr[in] == (r - l + 1)) return;
if (l == r) return void(tr[in] = sqrt(tr[in]));
update(lch, l, mid); update(rch, mid + 1, r);
tr[in] = tr[lch] + tr[rch];
}
ll qurry(int in = 1, int l = 1, int r = N) {
if (l > R || r < L) return 0;
if (L <= l && R >= r) return tr[in];
return qurry(lch, l, mid) + qurry(rch, mid + 1, r);
}
void solve() {
build();
scanf("%d", &M);
while (M--) {
int t; scanf("%d%d%d", &t, &L, &R);
if (L > R) L ^= R ^= L ^= R;
if (!t) update();
else printf("%lld\n", qurry());
}
}
int main() {
//freopen("in.txt", "r", stdin);
for (int __ = 1; ~scanf("%d", &N);) {
printf("Case #%d:\n", __++);
solve();
puts("");
}
}