【kuangbin带你飞】专题二十五 线段树 LCA 树链剖分

B
顺序发现线段树无法维护,逆序之后每个输入对(pos,val)的pos + 1既是队列前面需要的空位,线段树维护还留下的空位

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#include <vector>
using namespace std;
const int maxn = 2e5 + 5;

int a[maxn << 2], lzy[maxn << 2], n;
void pushUp(int rt) { a[rt] = a[rt << 1] + a[rt << 1 | 1]; }
void build(int rt = 1, int l = 1, int r = n) {
    if(l == r) {
        a[rt] = 1;
        lzy[rt] = 0;
        return;
    }
    int mid = l + r >> 1;
    build(rt << 1, l, mid);
    build(rt << 1 | 1, mid + 1, r);
    pushUp(rt);
}
void update(int pos, int val, int rt = 1, int l = 1, int r = n) {
    if(l == r) {
        a[rt]--;
        lzy[rt] = val;
        return;
    }
    int mid = l + r >> 1;
    if(a[rt << 1] >= pos) update(pos, val, rt << 1, l, mid);
    else update(pos - a[rt << 1], val, rt << 1 | 1, mid + 1, r);
    pushUp(rt);
}
vector<int> ans;
void solve(int rt = 1, int l = 1, int r = n) {
    if(l == r) {
        ans.push_back(lzy[rt]);
        return;
    }
    int mid = l + r >> 1;
    solve(rt << 1, l, mid);
    solve(rt << 1 | 1, mid + 1, r);
}
pair<int, int> in[maxn];
int main()
{
    while(~scanf("%d", &n)) {
        for(int i = 1; i <= n; ++i)
            scanf("%d%d", &in[i].first, &in[i].second);
        build();
        for(int i = n; i >= 1; --i) {
            update(in[i].first + 1, in[i].second);
        }
        ans.clear();
        solve();
        for(int i = 0; i < n; ++i) i == 0 ? printf("%d", ans[i]) : printf(" %d", ans[i]);
        printf("\n");
    }
}

C
线段树区间更新

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#include <vector>
using namespace std;
const int maxn = 5e4 + 5;

int n, m;
struct node {
    int sum, lsum, rsum, lzy;
} a[maxn << 2];
void pushUp(int rt, int l, int r) {
    if(l == r) return;
    a[rt].sum = max(a[rt << 1].sum, a[rt << 1 | 1].sum);
    a[rt].lsum = a[rt << 1].lsum;
    a[rt].rsum = a[rt << 1 | 1].rsum;
    int mid = l + r >> 1;
    if(a[rt << 1].lsum == mid - l + 1) a[rt].lsum += a[rt << 1 | 1].lsum;
    if(a[rt << 1 | 1].rsum == r - mid) a[rt].rsum += a[rt << 1].rsum;
    a[rt].sum = max(a[rt].sum, a[rt << 1].rsum + a[rt << 1 | 1].lsum);
}
void pushDown(int rt, int l, int r) {
    if(a[rt].lzy == -1) return;
    if(l == r) return;
    int mid = l + r >> 1;
    a[rt << 1].lzy = a[rt << 1 | 1].lzy = a[rt].lzy;
    if(a[rt].lzy) {
        a[rt << 1].sum = a[rt << 1].lsum = a[rt << 1].rsum = mid - l + 1;
        a[rt << 1 | 1].sum = a[rt << 1 | 1].lsum = a[rt << 1 | 1].rsum = r - mid;
    }
    else {
        a[rt << 1].sum = a[rt << 1].lsum = a[rt << 1].rsum = 0;
        a[rt << 1 | 1].sum = a[rt << 1 | 1].lsum = a[rt << 1 | 1].rsum = 0;
    }
    a[rt].lzy = -1;
}
void build(int rt = 1, int l = 1, int r = n) {
    a[rt].lzy = -1;
    if(l == r) {
        a[rt].sum = a[rt].lsum = a[rt].rsum = 1;
        return;
    }
    int mid = l + r >> 1;
    build(rt << 1, l, mid);
    build(rt << 1 | 1, mid + 1, r);
    pushUp(rt, l, r);
}
int query(int k, int rt = 1, int l = 1, int r = n) {
    pushDown(rt, l, r);
    if(l == r) return l;
    int mid = l + r >> 1;
    if(a[rt << 1].sum >= k) return query(k, rt << 1, l, mid);
    else if(a[rt << 1].rsum + a[rt << 1 | 1].lsum >= k) return mid - a[rt << 1].rsum + 1;
    else return query(k, rt << 1 | 1, mid + 1, r);
}
void update(int L, int R, int op, int rt = 1, int l = 1, int r = n) {
    if(L <= l && r <= R) {
        if(op) {
            a[rt].lzy = 1;
            a[rt].sum = a[rt].lsum = a[rt].rsum = r - l + 1;
        }
        else {
            a[rt].lzy = 0;
            a[rt].sum = a[rt].lsum = a[rt].rsum = 0;
        }
        return;
    }
    pushDown(rt, l, r);
    int mid = l + r >> 1;
    if(mid >= L) update(L, R, op, rt << 1, l, mid);
    if(mid < R) update(L, R, op, rt << 1 | 1, mid + 1, r);
    pushUp(rt, l, r);
}

int main()
{
    scanf("%d%d", &n, &m);
    build();
    for(int i = 0; i < m; ++i) {
        int op, x, y;
        scanf("%d", &op);
        if(op == 1) {
            scanf("%d", &x);
            if(a[1].sum < x) {
                printf("0\n");
            }
            else {
                int res = query(x);
                update(res, res + x - 1, 0);
                printf("%d\n", res);
            }
        }
        else {
            scanf("%d%d", &x, &y);
            update(x, min(x + y - 1, n), 1);
        }
    }
}

D
线段树扫描线

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#include <vector>
using namespace std;
const int maxn = 2000 + 5;

int n;
vector<double> hsh;
int getId(double x) { return lower_bound(hsh.begin(), hsh.end(), x) - hsh.begin(); }
struct in_node {
    double l, r, h;
    int flg;
    in_node() {}
    in_node(double _l, double _r, double _h, int _flg) : l(_l), r(_r), h(_h), flg(_flg) {}
    bool operator <(const in_node& x) const {
        return h < x.h;
    }
} in[maxn << 1];

struct segmentTreeNode {
    int cnt;
    double len;
} tre[maxn << 2];
void pushup(int rt, int l, int r) {
    if(tre[rt].cnt) tre[rt].len = hsh[r + 1] - hsh[l];
    else if(l == r) tre[rt].len = 0;
    else tre[rt].len = tre[rt << 1].len + tre[rt << 1 | 1].len;
}
void build(int rt = 1, int l = 0, int r = hsh.size() - 1) {
    tre[rt].cnt = tre[rt].len = 0;
    if(l == r) return;
    int mid = l + r >> 1;
    build(rt << 1, l, mid);
    build(rt << 1 | 1, mid + 1, r);
}
void update(int L, int R, int val, int rt = 1, int l = 0, int r = hsh.size() - 1) {
    if(L <= l && r <= R) {
        tre[rt].cnt += val;
        pushup(rt, l, r);
        return;
    }
    int mid = l + r >> 1;
    if(mid >= L) update(L, R, val, rt << 1, l, mid);
    if(mid < R) update(L, R, val, rt << 1 | 1, mid + 1, r);
    pushup(rt, l, r);
}
int main()
{
    int cas = 1;
    while(~scanf("%d", &n)) {
        if(n == 0) break;
        hsh.clear();

        int tot = 0;
        double lx, ly, rx, ry;
        for(int i = 0; i < n; ++i) {
            scanf("%lf%lf%lf%lf", &lx, &ly, &rx, &ry);
            hsh.push_back(lx);
            hsh.push_back(rx);
            in[tot++] = in_node(lx, rx, ly, 1);
            in[tot++] = in_node(lx, rx, ry, -1);
        }
        sort(hsh.begin(), hsh.end());
        hsh.erase(unique(hsh.begin(), hsh.end()), hsh.end());
        build();
        sort(in, in + tot);
        double area = 0;
        for(int i = 0; i < tot; ++i) {
            update(getId(in[i].l), getId(in[i].r) - 1, in[i].flg);
            area += tre[1].len * (in[i + 1].h - in[i].h);
        }
        printf("Test case #%d\nTotal explored area: %.2f\n\n", cas++, area);
    }
}

F
主席树区间第k大

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#include <vector>
using namespace std;
const int maxn = 100000 + 5;

vector<int> hsh;
int getId(int x) { return lower_bound(hsh.begin(), hsh.end(), x) - hsh.begin(); }
int root[maxn], cnt;
struct seg {
    int lson, rson, num;
} tre[maxn * 40];
void update(int l, int r, int& rt, int& pre, int pos) {
    rt = ++cnt;
    tre[rt] = tre[pre];
    tre[rt].num++;
    if(l == r) return;
    int mid = l + r >> 1;
    if(pos <= mid) update(l, mid, tre[rt].lson, tre[pre].lson, pos);
    else update(mid + 1, r, tre[rt].rson, tre[pre].rson, pos);
}
int query(int l, int r, int pre, int now, int k) {
    if(l == r) return l;
    int mid = l + r >> 1;
    int num = tre[tre[now].lson].num - tre[tre[pre].lson].num;
    if(k <= num) return query(l, mid, tre[pre].lson, tre[now].lson, k);
    else return query(mid + 1, r, tre[pre].rson, tre[now].rson, k - num);
}
int a[maxn];
int main()
{
    int n, m;
    while(~scanf("%d%d", &n, &m)) {
        hsh.clear();
        for(int i = 1; i <= n; ++i) {
            scanf("%d", &a[i]);
            hsh.push_back(a[i]);
        }
        sort(hsh.begin(), hsh.end());
        hsh.erase(unique(hsh.begin(), hsh.end()), hsh.end());
        root[0] = cnt = 0;
        for(int i = 1; i <= n; ++i) {
            update(0, n - 1, root[i], root[i - 1], getId(a[i]));
        }
        while(m--) {
            int l, r, k;
            scanf("%d%d%d", &l, &r, &k);
            printf("%d\n", hsh[query(0, n - 1, root[l - 1], root[r], k)]);
        }
    }

}

G
线段树更新约瑟夫环

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#include <vector>
using namespace std;
const int maxn = 5e5 + 5;
int n, k;
int ip[] = {1, 2, 4, 6, 12, 24, 36, 48, 60, 120, 180, 240, 360, 720,
            840, 1260, 1680, 2520, 5040, 7560, 10080, 15120, 20160,
            25200, 27720, 45360, 50400, 55440, 83160, 110880,
            166320, 221760, 277200, 332640, 498960, 500001
           }; //反素数

int div1[] = {1, 2, 3, 4, 6, 8, 9, 10, 12, 16, 18, 20, 24, 30, 32, 36,
             40, 48, 60, 64, 72, 80, 84, 90, 96, 100, 108, 120,
             128, 144, 160, 168, 180, 192, 200
            };//反素数对应的约数个数
struct in_node {
    char name[15];
    int val;
} in[maxn];
int tre[maxn << 2];
void pushup(int rt) {
    tre[rt] = tre[rt << 1] + tre[rt << 1 | 1];
}
void build(int rt = 1, int l = 1, int r = n) {
    if(l == r) {
        tre[rt] = 1;
        return;
    }
    int mid = l + r >> 1;
    build(rt << 1, l, mid);
    build(rt << 1 | 1, mid + 1, r);
    pushup(rt);
}
int update(int k, int rt = 1, int l = 1, int r = n) {
    if(l == r) {
        tre[rt] = 0;
        return l;
    }
    int mid = l + r >> 1;
    int ret;
    if(tre[rt << 1] >= k) ret = update(k, rt << 1, l, mid);
    else ret = update(k - tre[rt << 1], rt << 1 | 1, mid + 1, r);
    pushup(rt);
    return ret;
}

int main()
{
    while(~scanf("%d%d", &n, &k)) {
        for(int i = 1; i <= n; ++i)
            scanf("%s%d", &in[i].name, &in[i].val);
        int m, cnt;
        for(int i = 0; ip[i] <= n; ++i) {
            m = ip[i];
            cnt = div1[i];
        }
        build();
        int res = n, pos;
        for(int i = 0; i < m; ++i) {
            res--;
            pos = update(k);
            if(res == 0) break;
            if(in[pos].val >= 0) k = (k - 1 + in[pos].val - 1) % res + 1;
            else k = ((k - 1 + in[pos].val) % res + res) % res + 1;
        }
        printf("%s %d\n", in[pos].name, cnt);
    }
}


H
旋转中序遍历

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 5;
const int mod = 1000000007;
typedef long long ll;
int n, son[maxn][2], fa[maxn], idx[maxn], ral[maxn], lr[maxn][2], w[maxn];
ll val[maxn], mul[maxn << 2];

void dfs(int x, int& dfn) {
    val[x] = w[x];
    if(son[x][0]) dfs(son[x][0], dfn), lr[x][0] = lr[son[x][0]][0], val[x] += val[son[x][0]];
    else lr[x][0] = dfn + 1;
    idx[x] = ++dfn;
    ral[dfn] = x;
    if(son[x][1]) dfs(son[x][1], dfn), lr[x][1] = lr[son[x][1]][1], val[x] += val[son[x][1]];
    else lr[x][1] = dfn;
    val[x] %= mod;
}
void pushup(int rt) {
    mul[rt] = mul[rt << 1] * mul[rt << 1 | 1] % mod;
}
void build(int rt = 1, int l = 1, int r = n) {
    if(l == r) {
        mul[rt] = val[ral[l]];
        return;
    }
    int mid = l + r >> 1;
    build(rt << 1, l, mid);
    build(rt << 1 | 1, mid + 1, r);
    pushup(rt);
}
ll query(int L, int R, int rt = 1, int l = 1, int r = n) {
    if(L <= l && r <= R) return mul[rt];
    int mid = l + r >> 1;
    ll res = 1;
    if(L <= mid) res = res * query(L, R, rt << 1, l, mid) % mod;
    if(mid < R) res = res * query(L, R, rt << 1 | 1, mid + 1, r) % mod;
    return res;
}
void update(int pos, ll v, int rt = 1, int l = 1, int r = n) {
    if(l == r) {
        mul[rt] = v;
        return;
    }
    int mid = l + r >> 1;
    if(pos <= mid) update(pos, v, rt << 1, l, mid);
    else update(pos, v, rt << 1 | 1, mid + 1, r);
    pushup(rt);
}
void LR(int x, int op) {
    if(son[x][op] == 0) return;
    int y = son[x][op];
    int bb = son[y][op ^ 1], cc = son[y][op];
    son[x][op] = bb;
    fa[bb] = x;
    int xx = fa[x];
    if(son[xx][0] == x) son[xx][0] = y;
    else son[xx][1] = y;
    fa[y] = xx;
    son[y][op ^ 1] = x;
    fa[x] = y;
    if(bb) lr[x][op] = lr[bb][op];
    else lr[x][op] = idx[x];
    lr[y][op ^ 1] = lr[x][op ^ 1];
    if(bb) val[x] = val[x]-val[y]+val[bb];
    else val[x] = val[x]-val[y];
    if(cc) val[y] = val[x]+val[cc]+w[y];
    else val[y] = val[x]+w[y];
    update(idx[x], val[x]);
    update(idx[y], val[y]);
}

int main()
{
    int t, m;
    scanf("%d", &t);
    for(int cas = 1; cas <= t; ++cas) {
        printf("Case #%d:\n", cas);
        scanf("%d%d", &n, &m);
        memset(fa, 0, sizeof(fa));
        son[0][0] = son[0][1] = 0;
        for(int i = 1; i <= n; ++i) {
            scanf("%d%d%d", &w[i], &son[i][0], &son[i][1]);
            fa[son[i][0]] = fa[son[i][1]] = i;
        }
        int dfn = 0;
        dfs(1, dfn);
        build();
        while(m--) {
            int op, x;
            scanf("%d%d", &op, &x);
            if(op == 2) printf("%lld\n", query(lr[x][0], lr[x][1]));
            else LR(x, op);
        }
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值