Example Problems segment tree (Collection)

There are seven questions, will continue to update ...

Difficulty from easy to difficult roughly, (although the giant guy who for both water problem) ...

English side have title problems that Italy briefly (Tip:! HDU topic note sets of data are otherwise miserable pit)

POJ3321 Apple Tree

Meaning of the questions: Given a tree, there are two: 1, the number of nodes on a ^ 1 (if 1 to 0, 0 to 1) 2, the query to a node is the root of child number 1 in the tree

Modify and query a single point in a tree, again as long as dfs, dfs recording the order of each point can be transformed to a maintenance problem chain segment tree

Change and template, border dfs sequence and the last node of the first node when the query to each of them as a sub-tree traversal query section (DFS order every single child nodes in the tree is continuous)

#include <stdio.h>
#include <iostream>
using namespace std;
inline void read (int &x) {
    char ch = getchar(); x = 0;
     while (!isdigit(ch)) ch = getchar();
     while (isdigit(ch)) x = x * 10 + ch - 48, ch = getchar();
}
void print (int x) {
    if (x > 9) print (x / 10);
    putchar (x % 10 + 48);
}
const int N = 1e6 + 10;
int n, cnt, tot, m, pos, ql, qr, s[N << 2], num[N], l[N], r[N], nxt[N << 1], to[N << 1], h[N];
inline void add (int u, int v) {
    to[++tot] = v, nxt[tot] = h[u], h[u] = tot;
}
void dfs (int u, int la) {
    num[u] = l[u] = ++ cnt;
    for (int i = h[u]; i; i = nxt[i]) if (to[i] != la) dfs (to[i], u);
    r[u] = cnt;  //l、r记录每颗子树中最小和最大的dfs序
}
#define ls p << 1
#define rs p << 1 | 1
void build (int p, int l, int r) {
    if (l == r) {s[p] = 1; return;}
    int mid (l + r >> 1);
    build (ls, l, mid), build (rs, mid + 1, r);
    s[p] = s[ls] + s[rs];
}
void change (int p, int l, int r) {
    if (l == r) {s[p] ^= 1; return;} //把0改为1,把1改为0,相当于当前数字^1
    int mid (l + r >> 1);
    pos <= mid ? change (ls, l, mid) : change (rs, mid + 1, r);
    s[p] = s[ls] + s[rs];
}
int query (int p, int l, int r) {
    if (ql <= l && qr >= r) return s[p];
    int mid (l + r >> 1), t (0);
    if (ql <= mid) t += query (ls, l, mid);
    if (qr > mid) t += query (rs, mid + 1, r);
    return t;
}
int main() {
    read (n);
    for (int i = 1, u, v; i < n; ++i)
        read (u), read (v), add (u, v), add (v, u);
    dfs (1, 0); build (1, 1, n);
    read (m);
    for (int i = 1; i <= m; ++i) {
        char ch = getchar(); getchar();
        if (ch == 'C') read (pos), pos = num[pos], change (1, 1, n);
        else read (pos), ql = l[pos], qr = r[pos], print (query (1, 1, n)), puts ("");
    }
    return 0;
}

CF920F SUM and REPLACE

And differs in that when the template is to modify the number of each divisor number, difficult to find, when a number of x <= 2, x is equal to the number itself and about the number, how many times does not modify the multi- change

Preprocessing the first number of each divisor number, maintenance interval maximum value with the segment tree, if <= 2, then terminates the recursive

For> 2 number of modifications to be violent, but because of the number of divisor of each number drops quickly, after a few drops <= 2, so the complexity is excellent (about nlogn?)

This problem with CF438D and Sequence of The Child (section modulus), and is similarly maintenance interval maximum value

CF920F:

#include <bits/stdc++.h>
using namespace std;
#define rg register
#define ll long long
inline void read (int &x) {
    char ch = getchar(); x = 0;
    while (!isdigit(ch)) ch = getchar();
    while (isdigit(ch))  x = x * 10 + ch - 48, ch = getchar();
}
void print (ll x) {
    if (x > 9) print (x / 10);
    putchar (x % 10 + 48);
}
const int N = 3e5 + 10, M = 1e6;
int n, m, opt, ql, qr, cnt, maxn, p[N], a[N], k[M + 10], num[M + 10], c[N << 2];
ll s[N << 2];
inline void pre_work () {
    num[1] = 1;
    for (rg int i = 2; i <= maxn; ++i) {
        if (!k[i]) p[++cnt] = i, num[i] = 2;
        for (rg int j = 1; j <= cnt && p[j] * i <= maxn; ++j) {
            int tmp (p[j] * i), t (0);
            while (tmp % p[j] == 0) ++t, tmp /= p[j];
            k[p[j] * i] = 1, num[p[j] * i] = num[tmp] * (t + 1);
            if (i % p[j] == 0) continue;
        }
    }
}
#define ls p << 1
#define rs p << 1 | 1
inline int Max (int a, int b) {return a > b ? a : b;}
inline void push_up (int p) {
    s[p] = s[ls] + s[rs], c[p] = Max (c[ls], c[rs]);
}
void build (int p, int l, int r) {
    if (l == r) {c[p] = s[p] = a[l]; return;}
    int mid = l + r >> 1;
    build (ls, l, mid), build (rs, mid + 1, r);
    push_up (p);
}
void update (int p, int l, int r) {
    if (c[p] <= 2) return;
    if (l == r) {c[p] = s[p] = num[c[p]]; return;}
    int mid = l + r >> 1;
    if (ql <= mid) update (ls, l, mid);
    if (qr > mid) update (rs, mid + 1, r);
    push_up (p);
}
ll ask (int p, int l, int r) {
    if (ql <= l and qr >= r) return s[p];
    ll s (0);  int mid = l + r >> 1;
    if (ql <= mid) s += ask (ls, l, mid);
    if (qr > mid) s += ask (rs, mid + 1, r);
    return s;
}
int main() {
    read (n), read (m);
    for (rg int i = 1; i <= n; ++i) read (a[i]), maxn = Max (maxn, a[i]);
    pre_work (), build (1, 1, n);
    for (rg int i = 1; i <= m; ++i) {
        read (opt);
        if (opt == 1) read (ql), read (qr), update (1, 1, n);
        else read (ql), read (qr), print (ask (1, 1, n)), puts ("");
    }
    return 0;
}

CF438D:

#include <bits/stdc++.h>
using namespace std;
#define rg register
#define ll long long
inline void read (int &x) {
    char ch = getchar(); x = 0;
    while (!isdigit(ch)) ch = getchar();
    while (isdigit(ch))  x = x * 10 + ch - 48, ch = getchar();
}
void print (ll x) {
    if (x > 9) print (x / 10);
    putchar (x % 10 + 48);
}
const int N = 1e5 + 10;
int n, m, opt, ql, qr, mod, val, pos, a[N], c[N << 2];
ll s[N << 2];
#define ls p << 1
#define rs p << 1 | 1
inline int Max (int a, int b) {return a > b ? a : b;}
inline void push_up (int p) {
    s[p] = s[ls] + s[rs], c[p] = Max (c[ls], c[rs]);
}
void build (int p, int l, int r) {
    if (l == r) {c[p] = s[p] = a[l]; return;}
    int mid = l + r >> 1;
    build (ls, l, mid), build (rs, mid + 1, r);
    push_up (p);
}
void update (int p, int l, int r) {
    if (c[p] < mod) return;
    if (l == r) {c[p] %= mod, s[p] %= mod; return;}
    int mid = l + r >> 1;
    if (ql <= mid) update (ls, l, mid);
    if (qr > mid) update (rs, mid + 1, r);
    push_up (p);
}
void change (int p, int l, int r) {
    if (l == r) {c[p] = s[p] = val; return;}
    int mid = l + r >> 1;
    (pos <= mid) ? change (ls, l, mid) : change (rs, mid + 1, r);
    push_up (p);
}
ll ask (int p, int l, int r) {
    if (ql <= l and qr >= r) return s[p];
    ll s (0);  int mid = l + r >> 1;
    if (ql <= mid) s += ask (ls, l, mid);
    if (qr > mid) s += ask (rs, mid + 1, r);
    return s;
}
int main() {
    read (n), read (m);
    for (rg int i = 1; i <= n; ++i) read (a[i]);
    build (1, 1, n);
    for (rg int i = 1; i <= m; ++i) {
        read (opt);
        if (opt == 1) {
            read (ql), read (qr);
            print (ask (1, 1, n)), puts ("");
        }
        else if (opt == 2) {
            read (ql), read (qr), read (mod);
            update (1, 1, n);
        }
        else {
            read (pos), read (val);
            change (1, 1, n);
        }
    }
    return 0;
}

HDU2795 Billboard

The meaning of problems: row w h a rectangular column, placed horizontally inside the stripe size m is 1 * l [i] of the small rectangle, not overlap, if fit, the minimum number of output lines can be put down, the output does not fit -1

Since only m rectangles, only a maximum of m rows (h great range), m taking on the h min

Then the maximum value of the maintenance interval of each line and the rest, if the query maximum left subtree> desired length, the left sub-tree recursively, otherwise considered the right subtree, if the length is not enough, the answer is -1

#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
inline void read (int &x) {
    char ch = getchar(); x = 0;
    while (!isdigit(ch)) ch = getchar();
    while (isdigit(ch))  x = x * 10 + ch - 48, ch = getchar();
}
inline int print (int x) {
    if (x < 0) putchar ('-'), x = -x;
    if (x > 9) print (x / 10);
    putchar (x % 10 + 48);
}
int h, w, n, val, c[N << 2];
#define ls p << 1
#define rs p << 1 | 1
inline int Max (int a, int b) {return a > b ? a : b;}
int query (int p, int l, int r, int val) {
    if (l == r) {
        if (c[p] >= val) {c[p] -= val; return l;}
        else return -1;
    }
    int mid (l + r >> 1), ans (-1);
    if (c[ls] >= val) ans = query (ls, l, mid, val);
    else if (c[rs] >= val) ans = query (rs, mid + 1, r, val);
    c[p] = Max (c[ls], c[rs]);
    return ans;
}
int main() {
    while (~scanf ("%d %d %d", &h, &w, &n)) {
        if (n < h) h = n;
        for (int i = 1; i <= (h << 2); ++i) c[i] = w;
        for (int i = 1; i <= n; ++i) {
            read (val);
            if (val > w) puts ("-1");
            else print (query (1, 1, h, val)), puts ("");
        }
    }
    return 0;
}

POJ1151 Atlantis

Title template scanning lines, find a number of rectangular footprint

Each of the left and right sides of the rectangle removed (the upper and lower vertically taken to do the same, the method mentioned here do sideways), to obtain 2n line segments, the line segments sorted by the abscissa coordinate

For discrete ordinate, ordinate all values ​​can be at most 2n species, just consider these ordinate consisting of the line can

Maintenance interval length covered segment number and interval are covered with a number of segments, current = length covered is covered more than once and the line segment

All modifications are pairs (ordinate border two sides of the same), this issue is not required under the lazy pass mark (you can get a set of hands to count the data and found that you do not need downstream),

Through all the segments, each time statistical answers, plus the difference between the total length of the current ordinate covered two segments *

Also here upward statistics (push_up function) rather special

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
const int N = 410;
int n, m, T, c[N << 2];
double ans, xa[N], ya[N], xb[N], yb[N], ty[N << 1], len[N << 2];
struct e {
    double x;
    int ya, yb, val;
    bool operator <(const e &t) const {return x < t.x;}
} q[N << 1];
inline int find (double val) {
    int l (1), r (m), mid;
    while (l <= r) {
        mid = l + r >> 1;
        if (ty[mid] == val) return mid;
        if (ty[mid] < val) l = mid + 1;
        else r = mid - 1;
    }
}
#define ls p << 1
#define rs p << 1 | 1
void push_up (int p, int l, int r) {
    if (c[p]) len[p] = ty[r + 1] - ty[l];
    else if (l == r) len[p] = 0;
    else len[p] = len[ls] + len[rs];
}
void update (int p, int l, int r, int ql, int qr, int v) {
    if (ql <= l && qr >= r) {
        c[p] += v, push_up (p, l, r); return;
    }
    int mid (l + r >> 1);
    if (ql <= mid) update (ls, l, mid, ql, qr, v);
    if (qr > mid) update (rs, mid + 1, r, ql, qr, v);
    push_up (p, l, r);
}
int main() {
    while (1) {
        scanf ("%d", &n);
        if (!n) break;
        int t = n << 1;
        ans = 0; m = 1;
        memset (c, 0, sizeof (c));
        memset (len, 0, sizeof (len));
        if (!n) break;
        for (int i = 1; i <= n; ++i) scanf ("%lf %lf %lf %lf", xa + i, ya + i, xb + i, yb + i);
        for (int i = 1; i <= n; ++i) q[i].x = xa[i], q[n + i].x = xb[i], q[i].val = 1, q[n + i].val = -1;
        for (int i = 1; i <= n; ++i) ty[i] = ya[i], ty[n + i] = yb[i];
        sort (ty + 1, ty + t + 1);
        for (int i = 2; i <= t; ++i) if (ty[i] != ty[i - 1]) ty[++m] = ty[i];
        for (int i = 1; i <= n; ++i)
          q[i].ya = q[n + i].ya = find (ya[i]), q[i].yb = q[n + i].yb = find (yb[i]);
        sort (q + 1, q + t + 1);
        for (int i = 1; i < t; ++i) {
            update (1, 1, m, q[i].ya, q[i].yb - 1, q[i].val);
            ans += len[1] * (q[i + 1].x - q[i].x);
        }
        printf("Test case #%d\nTotal explored area: %.2lf\n\n", ++T, ans);
    }
    return 0;
}

HDU1225 area covered

Different problems upgraded version of the scan lines, and the scanning line template, this problem is only more than twice the area of ​​coverage to be credited to the total, so some complicated issues

However, different steps only statistical and maintenance information needs little change, where maintenance is required to be covered> = 1 length and are covered> = 2 times the length (because the cover> = 2 times the length of the beginning of the cover 1 the come)

push_up function of this problem is more strange, need to be discussed division multiple categories

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
const int N = 2010;
int t, n, m, c[N << 2];
double xl, xr, yl[N], yr[N], res, s[N], len1[N << 2], len2[N << 2];
struct e {
    double x;
    int l, r, val;
    bool operator <(const e &t) const {return x < t.x;}
} q[N];
inline int find (double x) {
    int l (1), r (m), mid;
    while (l <= r) {
        mid = l + r >> 1;
        if (s[mid] == x) return mid;
        if (s[mid] < x) l = mid + 1;
        else r = mid - 1;
    }
}
#define ls p << 1
#define rs p << 1 | 1
inline void push_up (int p, int l, int r) {
    if (c[p]) len1[p] = s[r + 1] - s[l];
    else if (l == r) len1[p] = 0;
    else len1[p] = len1[ls] + len1[rs];
    if (c[p] > 1) len2[p] = s[r + 1] - s[l];
    else if (l == r) len2[p] = 0;
    else if (!c[p]) len2[p] = len2[ls] + len2[rs];
    else len2[p] = len1[ls] + len1[rs];
}
void update (int p, int l, int r, int ql, int qr, int val) {
    if (ql <= l && qr >= r) {
        c[p] += val; push_up (p, l, r); return;
    }
    int mid (l + r >> 1);
    if (ql <= mid) update (ls, l, mid, ql, qr, val);
    if (qr > mid) update (rs, mid + 1, r, ql, qr, val);
    push_up (p, l, r);
}
int main() {
    scanf ("%d", &t);
    while (t--) {
        res = 0, m = 1;
        scanf ("%d", &n);
        memset (c, 0, sizeof (c));
        memset (len1, 0, sizeof (len1));
        memset (len2, 0, sizeof (len2));
        for (int i = 1; i <= n; ++i) {
            scanf ("%lf %lf %lf %lf", &xl, &yl[i], &xr, &yr[i]);
            s[i] = yl[i], s[n + i] = yr[i];
            q[i].x = xl, q[n + i].x = xr, q[i].val = 1, q[n + i].val = -1;
        }
        int t = n << 1;
        sort (s + 1, s + t + 1);
        for (int i = 2; i <= t; ++i)
          if (s[i] != s[i - 1]) s[++m] = s[i];
        for (int i = 1; i <= n; ++i)
          q[i].l = q[n + i].l = find (yl[i]), q[i].r = q[n + i].r = find (yr[i]);
        sort (q + 1, q + t + 1);
        for (int i = 1; i < t; ++i) {
            update (1, 1, m - 1, q[i].l, q[i].r - 1, q[i].val);
            res += len2[1] * (q[i + 1].x - q[i].x);
        }
        printf ("%.2lf\n", res);
    }
    return 0;
}

POJ2892 Tunnel Warfare

The meaning of problems: there is a chain attached to adjacent nodes (1 and 2,2 and 3, ... n-1 and n are connected), there are three modes of operation: 1, destruction of a node 2, from a certain point Q. how many points to that point with no damaged (including their own) 3, is currently rebuilding a ruined last point

Establishing maintenance segment tree can reach every point around the boundary (the initial values ​​are 1, n), when a damage point k (k is provided to reach the left and right borders of l1, r1), the interval l1 to k-1 the right boundary is modified to point k, k the left boundary point in the interval 1 + r1 to modify k

A sequence that disrupts the stack memory point, a reconstruction point, remove the top of the stack p (p is provided to reach the left and right boundaries of l2, R2), the right boundary point in the section k-1 l2 to modify r2, the left boundary point in the interval k + 1 to be modified to l2 r2

Directly query about +1 to the boundary and then subtract

(Konjac code may not be highly readable, but the main part is quite clear)

#include <stdio.h>
#include <iostream>
using namespace std;
inline void read (int &x) {
    char ch = getchar(); x = 0;
    while (!isdigit(ch)) ch = getchar();
    while (isdigit(ch)) x = x * 10 + ch - 48, ch = getchar();
}
void print (int x) {
    if (x > 9) print (x / 10);
    putchar (x % 10 + 48);
}
const int N = 5e4 + 10;
int n, m, x, top, st[N], ll[N], rr[N], k[N], cl[N << 3], cr[N << 3];
char ch[5];
#define ls p << 1
#define rs p << 1 | 1
inline void push_down (int p) {
    if (cl[p]) cl[ls] = cl[rs] = cl[p], cl[p] = 0;
    if (cr[p]) cr[ls] = cr[rs] = cr[p], cr[p] = 0;
}
void build (int p, int l, int r) {
    if (l == r) {cl[l] = 1, cr[l] = n; return;}
    int mid (l + r >> 1);
    build (ls, l, mid), build (rs, mid + 1, r);
}
void update1 (int p, int l, int r, int ql, int qr, int v) {      //修改右边界
    if (ql <= l && qr >= r) {cr[p] = v; return;}
    if (l == r) {rr[l] = cr[p]; return;}
    push_down (p);
    int mid (l + r >> 1);
    if (ql <= mid) update1 (ls, l, mid, ql, qr, v);
    if (qr > mid) update1 (rs, mid + 1, r, ql, qr, v);
}
void update2  (int p, int l, int r, int ql, int qr, int v) {     //修改左边界
    if (ql <= l && qr >= r) {cl[p] = v; return;}
    if (l == r) {ll[l] = cl[p]; return;}
    push_down (p);
    int mid (l + r >> 1);
    if (ql <= mid) update2 (ls, l, mid, ql, qr, v);
    if (qr > mid) update2 (rs, mid + 1, r, ql, qr, v);
}
void query (int p, int l, int r, int pos) { //使这个点的所有懒标记更新(更新为真实值)
    if (l == r) {ll[l] = cl[p], rr[l] = cr[p]; return;}
    push_down (p);
    int mid (l + r >> 1);
    pos <= mid ? query (ls, l, mid, pos) : query (rs, mid + 1, r, pos);
}
int main() {
    read (n), read (m);
    build (1, 1, n);
    for (int i = 1; i <= n; ++i) ll[i] = 1, rr[i] = n;
    while (m--) {
        scanf ("%s", ch);
        if (ch[0] == 'D') {
            read (x);
            st[++top] = x, k[x] = 1, query (1, 1, n, x);
            update1 (1, 1, n, ll[x] - (ll[x] != 1), x - 1, x - 1);
            update2 (1, 1, n, x + 1, rr[x] + (rr[x] != n), x + 1);
        }
        else if (ch[0] == 'Q') {
            read (x);
            if (k[x]) puts ("0");
            else query (1, 1, n, x), print (rr[x] - ll[x] + 1), puts ("");
        }
        else {
            if (!top) continue;
            x = st[top--], k[x] = 0, query (1, 1, n, x);
            update1 (1, 1, n, ll[x] - (ll[x] != 1), x - 1, rr[x]);
            update2 (1, 1, n, x + 1, rr[x] + (rr[x] != n), ll[x]);
        }
    }
    return 0;
}

HDU3016 Man Down

The meaning of problems: there are n pieces of line horizontally in a plane, each segment is given height, and energy left end position (positive or negative), initially in the line and has a highest point 100 on the energy and the current line segment and the energy of every possible vertical drop (may fall on other segments may also fall to the ground), then obtain the energy segment fell on the other line and continue the game from the line to the left or right, fall to the ground if the game is terminated , and the score of the current energy. But any one time must be positive energy, when the energy <= 0 has failed to terminate the game. If fall to the ground, the maximum score is output, if the output is not -1

This question my approach is rather peculiar (stupid)

0 is assumed for the ground segment, each segment will point to the other two segments (left and right end reaches the segment from falling), connected between the line side of an ED can be seen, the edge length may be on a line arriving energy said that this was built out of a directed graph, the line ran Spfa obtained the highest number of 0 to longest road is the answer (in fact solve this problem just fine with dp)

The key is obtained from each segment will reach around two falls which two segments: the above segments can be covered below, so according to height from the lowest to highest, followed by the update, you can find the query number two segments . For example when, according to the height of the current line has been sorted, the processing to a left end point 5, the right end point of the line segment 10 i, the first line segment tree à 5,10 query, then the interval is modified to the value of 5--10 i

#include <bits/stdc++.h>
using namespace std;
inline void read (int &x) {
    char ch = getchar(); int f = 0; x = 0;
    while (!isdigit(ch)) {if (ch == '-') f = 1; ch = getchar();}
    while (isdigit(ch)) x = x * 10 + ch - 48, ch = getchar();
    if (f) x = -x;
}
const int N = 1E5 + 10;
int n, cnt, M, c[N << 2], d[N], to[N][2], vis[N];
struct e {
    int h, l, r, val;
    bool operator < (const e &x) const {return h < x.h;}
} a[N];
#define ls p << 1
#define rs p << 1 | 1
inline void push_down (int p) {
    if (c[p]) c[ls] = c[rs] = c[p], c[p] = 0;
}
int update (int p, int l, int r, int ql, int qr, int val) {
    if (ql <= l && qr >= r) {c[p] = val; return 0;}
    push_down (p);
    int mid (l + r >> 1);
    if (ql <= mid) update (ls, l, mid, ql, qr, val);
    if (qr > mid) update (rs, mid + 1, r, ql, qr, val);
}
int query (int p, int l, int r, int pos) {
    if (l == r) return c[p];
    push_down (p);
    int mid (l + r >> 1);
    return pos <= mid ? query (ls, l, mid, pos) : query (rs, mid + 1, r, pos);
}
inline void Spfa () {
    queue <int> q;
    memset (d, 0xcf, sizeof (d));
    memset (vis, 0, sizeof (vis));
    d[n] = 100 + a[n].val, vis[n] = 1, q.push (n);
    while (!q.empty()) {
        int u = q.front ();
        vis[u] = 0, q.pop ();
        for (int i = 0; i <= 1; ++i) {
            int v = to[u][i];
            if (d[u] + a[v].val > d[v] && d[u] + a[v].val > 0) {
                d[v] = d[u] + a[v].val;
                if (!vis[v]) q.push (v), vis[v] = 1;
            }
        }
    }
}
int main() {
    while (~scanf ("%d", &n)) {
        cnt = M = 0;
        memset (c, 0, sizeof (c));
        for (int i = 1; i <= n; ++i)
            read (a[i].h), read (a[i].l), read (a[i].r), read (a[i].val), M = max (M, a[i].r);
        sort (a + 1, a + n + 1);
        for (int i = 1; i <= n; ++i) {
            int tl = query (1, 1, M, a[i].l), tr = query (1, 1, M, a[i].r);
            to[i][0] = tl, to[i][1] = tr;
            update (1, 1, M, a[i].l, a[i].r, i);
        }
        Spfa ();
        if (d[0] < 0) puts ("-1");
        else printf ("%d\n", d[0]);
    }
    return 0;
}

Guess you like

Origin www.cnblogs.com/whx666/p/12037809.html