zoukankan      html  css  js  c++  java
  • [kuangbin] 专题7 线段树 题解 + 总结

    [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. 敌兵布阵

    HDU - 1166

    思路:

    基础模板题

    三种思路:维护一个前缀数组,但容易超时、树状数组、线段树

    题解链接

    2. I Hate It

    HDU - 1754

    题意理解很简单,这里就说下注意点,数组要开大点不然容易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

    POJ - 3468

    思路:模板题,别敲错板子就行(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

    POJ - 2528

    线段树 + 离散化

    https://www.cnblogs.com/RioTian/p/13410156.html

    5. Just a Hook

    HDU - 1698

    题意:

    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

    ZOJ - 1610

    题解: https://www.cnblogs.com/RioTian/p/13410855.html

    7. Balanced Lineup

    POJ - 3264

    线段树 搭配注释理解

    #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?

    HDU - 4027

    线段树,保留有用的功能即可。

    #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("");
        }
    }
    

    Tips:时间会解决一切
  • 相关阅读:
    X 如何理解关系型数据库的常见设计范式?
    X 使用DMV,诊断和调优DB性能。
    X MSSQL-并发控制-2-Isolation msql 的各种隔离级别 sqlserver
    X SQL Server AG集群启动不起来的临时自救大招
    X 搭建非域AlwaysOn win2016+SQL2016
    X 从0开始搭建SQL Server AlwaysOn 第四篇(配置异地机房节点)
    X 从0开始搭建SQL Server AlwaysOn 第三篇(配置AlwaysOn)
    X 从0开始搭建SQL Server AlwaysOn 第二篇(配置故障转移集群)
    Python Cookie Session和分页
    Python django应用之corsheaders[跨域设置]
  • 原文地址:https://www.cnblogs.com/RioTian/p/13413897.html
Copyright © 2011-2022 走看看