• 线段树


    https://vjudge.net/contest/213797#problem/A习题集

    求区间最大值

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    
    const int maxmnode = 1 << 18;
    const int maxm = 5e4 + 5;
    
    
    struct NODE {
    int value;
    int left, right;
    } node[maxmnode];
    
    int index[maxm];
    
    void buildtree(int i, int left, int right) {
    node[i].left = left;
    node[i].right = right;
    node[i].value = 0;
    if(left == right) {
        index[left] = i;
        return;
    }
    buildtree(i << 1, left, (int)(floor(left + right) / 2.0));
    buildtree((i << 1) + 1, (int)(floor(left + right) / 2.0) + 1, right);
    }
    
    void updatetree(int ri) {
    if(ri == 1) return;
    int fi = ri / 2;
    int a = node[fi << 1].value;
    int b = node[ (fi << 1) + 1 ].value;
    node[fi].value = max(a, b);
    updatetree(fi);
    }
    
    int MAX;
    
    void query(int i, int l, int  r) {
    if(node[i].left == l && node[i].right == r) {
        MAX = max(MAX, node[i].value);
        return;
    }
    i = i << 1;
    if(l <= node[i].right) {
        if(r <= node[i].right) query(i, l, r);
        else query(i, l ,node[i].right);
    }
    i++;
    if(r >= node[i].left) {
        if(l >= node[i].left) query(i, l, r);
        else query(i, node[i].left, r);
    }
    
    }
    
    
    
    int main() {
    int n, m, q;
    while(~scanf("%d%d", &n, &m)) {
        buildtree(1, 1, n);
        for(int i = 1; i <= n; i++) {
            scanf("%d", &q);
            node[ index[i] ].value = q;
            updatetree(index[i]);
        }
        char ch[10];
        int a,b;
        while(m--) {
            scanf("%s%d%d", ch, &a, &b);
            if(ch[0] == 'Q') {
                MAX = 0;
                query(1, a, b);
                printf("%d
    ", MAX);
            }
            else {
                node[ index[a] ].value = b;//值无所谓,b;
                updatetree(index[a]);
            }
        }
    }
    
    
    return 0;
    }

    A - 敌兵布阵

     HDU - 1166

    求区间和。

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    
    const int maxm = 5e4 + 5;
    
    
    
    int sum[maxm << 2];
    
    
    void pushup(int rt) {
        sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];
    }
    
    void buildtree(int rt, int le, int ri) {
        if(le == ri) {
            scanf("%d", &sum[rt]);
            return;
        }
        int m = (le + ri) >> 1;
        buildtree(rt << 1, le, m);
        buildtree(rt << 1 | 1, m + 1, ri);
        pushup(rt);
    }
    void updatetree(int rt, int pos, int val, int le, int ri){
        if(le == ri){
            sum[rt] += val;
            return;
        }
        int m = (le + ri) >> 1;
        if(m >= pos) updatetree(rt << 1, pos, val, le, m);
        else updatetree(rt << 1 | 1, pos, val, m + 1, ri);
        pushup(rt);
    }
    
    int query(int rt, int l, int r, int le, int ri) {
        if(l <= le && r >= ri) {
            return sum[rt];
        }
        int ans = 0;
        int m = (le + ri) >> 1;
    //    if(r <= m) ans += query(rt << 1, l, r, le, m);
    //    else if(l > m) ans += query(rt << 1 | 1, l, r, m + 1, ri);
    //    else {
    //        ans += query(rt << 1, l, m, le, m);
    //        ans += query(rt << 1 | 1, m + 1, r, m + 1, ri);
    //    }
        if(l <= m) ans += query(rt << 1, l, r, le, m);
        if(r > m) ans += query(rt << 1 | 1, l, r, m + 1, ri);
        return ans;
    }
    int main() {
        int n, t;
        scanf("%d", &t);
        for(int k = 1; k <= t; k++) {
            printf("Case %d:
    ", k);
            scanf("%d", &n);
            buildtree(1, 1, n);
            char ch[10];
            int a, b;
            while(~scanf("%s", ch)) {
                if(ch[0] == 'E') break;
                scanf("%d%d", &a, &b);
                if(ch[0] == 'A') {
                    updatetree(1, a, b, 1, n);
                }
                else if(ch[0] == 'S') {
                    updatetree(1, a, -b, 1, n);
                }
                else {
                    printf("%d
    ", query(1, a, b, 1, n));
                }
            }
        }
        return 0;
    }

     I Hate It

     HDU - 1754 

    区间最大值。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    
    using namespace std;
    const int maxm = 2e5 + 5;
    
    int sum[maxm << 2];
    
    void pushup(int rt) {
        sum[rt] = max(sum[rt << 1], sum[rt << 1 | 1]);
    }
    
    void buildtree(int rt, int le, int re) {
        if(le == re) {
            scanf("%d", &sum[rt]);
            return;
        }
        int m = (le + re) >> 1;
        buildtree(rt << 1, le, m);
        buildtree(rt << 1 | 1, m + 1, re);
        pushup(rt);
    }
    
    void update(int rt, int pos, int val, int le, int re) {
        if(le == re) {
            sum[rt] = val;
            return;
        }
        int m = (le + re) >> 1;
        if(pos <= m) update(rt << 1, pos, val, le, m);
        else update(rt << 1 | 1, pos, val, m + 1, re);
        pushup(rt);
    }
    int query(int rt, int l ,int r, int le, int re) {
        if(l <= le && r >= re) {
            return sum[rt];
        }
        int m = (le + re) >> 1;
        int ans1 = 0;
    //    if(r <= m) ans1 = query(rt << 1, l, r, le, m);
    //    else if(l > m) ans1 = query(rt << 1 | 1, l, r, m + 1, re);
    //    else ans1 = max(query(rt << 1, l, m, le, m), query(rt << 1 | 1, m + 1, r, m + 1, re));
        if(l <= m) ans1 = max(ans1, query(rt << 1, l, r, le, m));
        if(r > m) ans1 = max(ans1, query(rt << 1 | 1, l, r, m + 1, re));
        return ans1;
    }
    int n, m;
    int main() {
        while(~scanf("%d%d", &n, &m)) {
            buildtree(1, 1, n);
            char ch[3];
            int x, y;
            while(m--) {
                scanf("%s", ch);
                if(ch[0] == 'Q') {
                    scanf("%d%d", &x, &y);
                    printf("%d
    ", query(1, x, y, 1, n));
                }
                else {
                    scanf("%d%d", &x, &y);
                    update(1, x, y, 1, n);
                }
            }
        }
    
        return 0;
    }

     区间修改加区间求和

    A Simple Problem with Integers

     POJ - 3468 

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    const int maxm = 1e5 + 5;
    ll sum[maxm << 2], add[maxm << 2];
    
    
    void pushup(int rt) {
        sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];
    }
    
    void pushdown(int rt, int m) {
        if(add[rt]) {
            add[rt << 1] += add[rt];
            add[rt << 1 | 1] += add[rt];
            sum[rt << 1] += add[rt] * (m - (m >> 1));
            sum[rt << 1 | 1] += add[rt] * (m >> 1);
            add[rt] = 0;
        }
    }
    
    void buildtree(int le, int re, int rt) {
        add[rt] = 0;
        if(le == re) {
            scanf("%lld", &sum[rt]);
            return;
        }
        int m = (le + re) >> 1;
        buildtree(le, m, rt << 1);
        buildtree(m + 1, re,  rt << 1 | 1);
        pushup(rt);
    }
    
    void updatetree(int c, int l ,int r, int rt, int le, int re) {
        if(l <= le && r >= re) {
            add[rt] += c;
            sum[rt] += (ll) c * (r - l + 1);
            return;
        }
    //    if(le == re) return;
        pushdown(rt, re - le + 1);
        int m = (le + re) >> 1;
        if(r <= m) updatetree(c, l, r, rt << 1, le, m);
        else if(l > m) updatetree(c, l, r, rt << 1 | 1, m + 1, re);
        else {
            updatetree(c, l, m, rt << 1, le, m);
            updatetree(c, m + 1, r, rt << 1 | 1, m + 1, re);
        }
        pushup(rt);
    }
    
    ll query(int l, int r, int rt, int le, int re) {
        if(l <= le && r >= re) return sum[rt];
        pushdown(rt, re - le + 1);
        int m = (le + re) >> 1;
        ll res = 0;
        if(r <= m) res += query(l, r, rt << 1, le, m);
        else if(l > m) res += query(l, r, rt << 1 | 1, m + 1, re);
        else {
            res += query(l, m, rt << 1, le, m);
            res += query(m + 1, r, rt << 1 | 1, m + 1, re);
        }
        return res;
    }
    
    int main() {
        int n, m;
        while(~scanf("%d%d", &n, &m)) {
            buildtree(1, n, 1);
            while(m--) {
                char ch[3];
                scanf("%s", ch);
                int a, b, c;
                if(ch[0] == 'Q') {
                    scanf("%d%d", &a, &b);
                    printf("%lld
    ", query(a, b, 1, 1, n));
                }
                else {
                    scanf("%d%d%d", &a, &b, &c);
                    updatetree(c, a, b, 1, 1, n);
                }
            }
        }
        return 0;
    }

    树状数组做法

    https://blog.csdn.net/SSL_ZYC/article/details/81940902

    这个博客里有讲解。

    可以当做树状数组区间修改,区间求和的模板。

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<cstring>
    #include<vector>
    #define maxx 100005
    using namespace std;
    int n,q;
    long long a[maxx];
    long long  c[2][maxx];
    void change(int k,int x,int p)
    {
        for(;x<=n;x+=x&-x)c[k][x]+=p;
    }
    
    long long query(int k,int x)
    {
        long long ans=0;
        for(;x;x-=x&-x)ans+=c[k][x];
        return ans;
    }
    long long query(int x)
    {
        return a[x]+(x+1)*query(0,x)-query(1,x);
    }
    int main()
    {
        cin>>n>>q;
        for(int i=1;i<=n;i++)
        {
            scanf("%lld",a+i);
            a[i]+=a[i-1];
        }
        char s[3];
        int l,r,d;
        while(q--)
        {
            scanf("%s",s);
            if(s[0]=='Q')
            {
                scanf("%d%d",&l,&r);
                printf("%lld
    ",query(r)-query(l-1));
            }
            else
            {
                scanf("%d%d%d",&l,&r,&d);
                change(0,l,d);
                change(0,r+1,-d);
                change(1,l,l*d);
                change(1,r+1,-(r+1)*d);
            }
        }
        return 0;
    }

     Mayor's posters  更染色问题很相像。区间染色,求最终某个区间内有几个颜色。

     离散化

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    
    using namespace std;
    const int maxm = 2e5 + 5;
    typedef pair<int, int> pii;
    
    
    int lazy[maxm << 3], col[maxm << 3], vis[maxm << 2];
    int res;
    int a[maxm << 3], b[maxm << 3];
    
    void pushdown(int rt) {
        if(lazy[rt]) {
            lazy[rt << 1] = lazy[rt << 1 | 1] = lazy[rt];
            col[rt << 1] = col[rt << 1 | 1] = lazy[rt];
        }
        lazy[rt] = 0;
    }
    
    void pushup(int rt) {
        if(col[rt << 1] == 0 || col[rt << 1 | 1] == 0) {
            col[rt] = 0;
        }
        if(col[rt << 1] != col[rt << 1 | 1]) {
            col[rt] = 0;
        }
        else col[rt] = col[rt << 1];
    }
    
    void build(int rt, int le, int re) {
        col[rt] = 0;
        lazy[rt] = 0;
        if(le == re) {
            return;
        }
        int m = (le + re) >> 1;
        build(rt << 1, le, m);
        build(rt << 1 | 1, m + 1, re);
    }
    
    void update(int rt, int l, int r, int val, int le, int re) {
        if(l <= le && r >= re) {
            lazy[rt] = val;
            col[rt] = val;
            return;
        }
        pushdown(rt);
        int m = (le + re) >> 1;
        if(r <= m) {
            update(rt << 1, l, r, val, le, m);
        }
        else if(l > m) {
            update(rt << 1 | 1, l, r, val, m + 1, re);
        }
        else {
            update(rt << 1, l, m, val, le, m);
            update(rt << 1 | 1, m + 1, r, val, m + 1, re);
        }
        pushup(rt);
    }
    
    void query(int rt, int l ,int r, int le, int re) {
        if(l <= le && r >= re && col[rt] && !vis[ col[rt] ]) {
            res++;
            vis[ col[rt] ] = 1;
            return;
        }
      if(l <= le && r >= re && col[rt] && vis[ col[rt] ]) return;
    if(le == re) { return; }//这个因为前面If判断并不完全包括这种情况,所以要特判一下,防止无限递归。可能这一整个数都没被更新过,所以col都为零,往下走。 pushdown(rt); int m = (le + re) >> 1; if(r <= m) query(rt << 1, l, r, le, m); else if(l > m) query(rt << 1 | 1, l, r, m + 1, re); else { query(rt << 1, l, m, le, m); query(rt << 1 | 1, m + 1, r, m + 1, re); } } int t, n; int main() { scanf("%d", &t); while(t--) { scanf("%d", &n); memset(vis, 0, sizeof(vis)); memset(lazy, 0, sizeof(lazy)); memset(col, 0, sizeof(col)); for(int i = 1; i <= 2 * n; i++) { scanf("%d", &a[i]); a[i + 2 * n] = a[i] + 1;
    //看下面的样例。 b[i]
    = a[i]; } sort(a + 1, a + 4 * n + 1); int ant = unique(a + 1, a + 4 * n + 1) - a; for(int i = 1; i <= 2 * n; i++) { b[i] = lower_bound(a + 1, a + ant, b[i]) - a; } build(1, 1, ant); for(int i = 1; i <= 2 * n; i += 2) { update(1, b[i], b[i + 1], i, 1, ant); } res = 0; query(1, 1, ant, 1, ant); printf("%d ", res); } return 0; }
    /*
    该题目的数据有点水,错误的离散化也可以过
    这里注意在离散化的时候不仅要保留相对大小关系,还要保证数据之间的连续性
    例如对于这组数据
    1 3 1 10 1 4 6 10
    离散化完之后是四个点,4和6之间的5在离散化的过程中消失了,但是因为第一次海报是1 10,所以5是有颜色的,
    但是维护离散化后的线段树没有该点的数据,普通离散化之后认为4和6是连续的了,应该每个点都插入一个+1的点,这样离散化能够保证连续性
    */

     Tunnel Warfare 题意:开始村庄是联通的,随意炸毁,或者修复刚炸毁的那个,,然后查询某个村庄的联通村庄数。村庄1-n.

     HDU - 1540 线段树单点更新,求最大连续子段和。

    线段树要记住pushup是从下面开始更新的

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    
    using namespace std;
    const int maxm = 50005;
    struct NODE {
        int l ,r;
        int li, ri, mi;
        //从左边开始的最大连续和,右边的,最终的最大连续和(也就是最大的)。
        int mid() {
            return (l + r) >> 1;
        }
    } node[maxm << 2];
    int n, k;
    int ro[maxm], num;
    char ch[2];
    
    
    void pushup(int ri) {
        if(node[ri << 1].li == node[ri << 1].r - node[ri << 1].l + 1) {
            node[ri].li = node[ri << 1].li + node[ri << 1 | 1].li;
        }
        //如果左孩子的左连续区间是满的(事实上其他的也是满的),那么父节点的左连续区间就等于左孩子的加上右孩子的(因为连在一起了)。
        else {
            node[ri].li = node[ri << 1].li;
         //不是满的就等于左孩子的左连续长度
        }
        if(node[ri << 1 | 1].ri == node[ri << 1 | 1].r - node[ri << 1 | 1].l + 1) {
            node[ri].ri = node[ri << 1 | 1].ri + node[ri << 1].ri;
        }
        else {
            node[ri].ri = node[ri << 1 | 1].ri;
        }
        node[ri].mi = max( max(node[ri << 1].mi, node[ri << 1 | 1].mi), node[ri << 1].ri + node[ri << 1 | 1].li );
        //最终的连续长度等于左边的最大连续长度,右边的最大连续长度,左边的右连续长度加上右边的左连续长度。
    }
    
    void build(int ri, int l, int r) {
        node[ri].l = l;
        node[ri].r = r;
        node[ri].li = node[ri].ri = node[ri].mi = r - l + 1;
        //开始时满的
        if(node[ri].l == node[ri].r) {
            node[ri].li = node[ri].ri = node[ri].mi = 1;
        //叶子节点是1.
            return;
        }
        int m = node[ri].mid();
        build(ri << 1, l, m);
        build(ri << 1 | 1, m + 1, r);
        pushup(ri);
    }
    
    void update(int ri, int pos, int flag) {
        if(node[ri].l == node[ri].r) {
            if(flag) {
        //在叶子节点更新。
                node[ri].li = node[ri].mi = node[ri].ri = 1;
            }
            else {
                node[ri].li = node[ri].mi = node[ri].ri = 0;
            }
            return;
        }
        int m = node[ri].mid();
        if(pos <= m) {
            update(ri << 1, pos, flag);
        }
        else {
            update(ri << 1 | 1, pos, flag);
        }
        pushup(ri); 
    }
    
    int query(int ri, int pos) {
        if(node[ri].l == node[ri].r || node[ri].mi == node[ri].r - node[ri].l + 1 || node[ri].mi == 0) {
            return node[ri].mi;
        }
        //如果是满的,为零,或者到了叶子节点就返回值。
        int m = node[ri].mid();
        if(pos <= m) {
            if(pos >= node[ri << 1].r - node[ri << 1].ri + 1) {
                return node[ri << 1].ri + node[ri << 1 | 1].li;
            }
        //如果在自己的左孩子右最大连续区间内,那么最大的连续长度就是自己的右边加上右边兄弟的左边的。(因为如果继续往下查肯定更小,而且如果自己左边的连续区间与右边的连续区间重合,那么这个区间就算完了。)
    //第一种,左孩子的左区间与右区间是分开的,那么这个点在左孩子中的最大连续字段就是右区间,然后自然可以加上右孩子的左区间。
    //第二种,左孩子的左区间与右区间是连在一起的,这种情况说明整个区间都是相连的,左右连续区间都是整个左孩子的长度。
    else { return query(ri << 1, pos); //继续查询左孩子。 } } else { if(pos <= node[ri << 1 | 1].l + node[ri << 1 | 1].li - 1) { return node[ri << 1].ri + node[ri << 1 | 1].li; } else { return query(ri << 1 | 1, pos); } } } int main() { while(~scanf("%d%d", &n, &k)) { build(1, 1, n); int x; while(k--) { scanf("%s", ch); if(ch[0] == 'D') { scanf("%d", &x); ro[num++] = x; //记录刚炸毁的那条。 update(1, x, 0); } else if(ch[0] == 'Q') { scanf("%d", &x); int ans = query(1, x); printf("%d ", ans); } else { int y = ro[--num]; update(1, y, 1); } } } return 0; }

    I - Infinite Inversions CodeForces - 540E

    题意:一个无限的自然数序列进行n次操作,每次交换其中2个位置上的数,求逆序数个数。

    题解:操作数很大,如果直接求逆序数个数会超时。而最多有1e5的操作次数,那么可以把点离散化,两个交换点之间加入新的点,该点的权值即是两个点之间的点的个数。离散化后用树状数组直接求其逆序数。

    相当于把区间转化成一个点,点的权值表示该区间里面元素的个数,然后在求逆序对。

    http://codeforces.com/problemset/problem/540/E

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    const int maxm = 5e5 + 5;
    struct Node
    {
        ll a,b;
    }node[maxm];
    ll n, cnt, len, tot;
    ll p[maxm], x[maxm], y[maxm], w[maxm], sum[maxm];
    ll lowbit(ll x)
    {
        return x & -x;
    }
    void add(ll x,ll v)
    {
        while(x <= maxm)
        {
            sum[x] += v;
            x += lowbit(x);
        }
    }
    ll getsum(ll x)
    {
        ll s = 0;
        while(x > 0)
        {
            s += sum[x];
            x -= lowbit(x);
        }
        return s;
    }
    int main() {
    scanf("%lld", &n);
    for(int i = 1; i <= n; i++) {
        scanf("%lld%lld", &node[i].a, &node[i].b);
        x[++cnt] = node[i].a;
        x[++cnt] = node[i].b;
    }
    sort(x + 1, x + cnt + 1);
    len = unique(x + 1, x + cnt + 1) - (x + 1);
    //unique函数排除重复元素,返回第一个重复元素的位置。
    for(int i = 1; i <= len; i++) { y[++tot] = x[i]; w[tot] = 1; if(x[i] + 1 < x[i + 1]) { y[++tot] = x[i] + 1; w[tot] = x[i + 1] - x[i] - 1; } } for(int i = 1; i <= tot; i++) p[i] = i; for(int i = 1; i <= n; i++) { ll p1 = lower_bound(y + 1, y + tot + 1, node[i].a) - y; ll p2 = lower_bound(y + 1, y + tot + 1, node[i].b) - y;
      //调换顺序。虽然是区间的那种点没有交换,但是后面求逆序数的时候会算到那些是区间的点。 swap(p[p1], p[p2]); }
    //上面都是离散化操作。 ll res
    = 0; for(int i = tot; i >= 1; i--) { res += w[p[i]] * getsum(p[i]); add(p[i],w[p[i]]);
    //从后面开始,相当于每个点都求一下逆序数。 } printf(
    "%lld ", res); return 0; }

    M - Decomposition into Good Strings

     Gym - 100971M 

    题意:好字符串就是一个字符串正好含有k个不同的字符,求该字符串的前缀,能够最少分成几个好字符串的拼接。

    解法:先求出每一位字符往前形成好字符串的范围,l[i] 到r[i],注意求左边是如果是k+1个的话要加2(手动模拟一下)其他情况只是加1.然后得到最大值之后,就一个一个遍历,同时更新该点的最小值,如果能够延伸到

    1的话,那肯定最小好字符串就是1.然后注意这个线段树区间是从零开始,因为查询时端点要用到0,把他设置为inf,因为是从1开始,所以只不会变,主要是为了防止越界错误。

    #include<bits/stdc++.h>
    
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pii;
    const int inf = 0x3f3f3f3f;
    const int mod = 1e9 + 7;
    const int maxm = 2e5 + 5;
    int sum[maxm << 2];
    struct Node {
        int l, r;
        int mid() {
            return (l + r) >> 1;
        }
    } node[maxm << 2];
    int k;
    char ch[maxm];
    int num[30];
    int l[maxm], r[maxm];
    int c[maxm];
    void pushup(int ri) {
    //    sum[ri] = min(sum[ri], min(sum[ri << 1], sum[ri << 1 | 1]));
    sum[ri] = min(sum[ri << 1], sum[ri << 1 | 1]);
    }
    
    void build(int ri, int ll, int rr) {
    //    printf("sn
    ");
        node[ri].l = ll, node[ri].r = rr;
        sum[ri] = inf;
        if(ll == rr) return;
        int m = node[ri].mid();
        build(ri << 1, ll, m);
        build(ri << 1 | 1, m + 1, rr);
    }
    
    void update(int ri, int ind, int val) {
    //    printf("zx
    ");
        if(node[ri].l == node[ri].r) {
            sum[ri] = val;
            return;
        }
        int m = node[ri].mid();
        if(ind <= m) {
            update(ri << 1, ind, val);
        }
        else if(ind > m) {
            update(ri << 1 | 1, ind, val);
        }
        pushup(ri);
    }
    
    int query(int ri, int ll, int rr) {
    //    printf("dc
    ");
        if(node[ri].l == ll && node[ri].r == rr) {
            return sum[ri];
        }
        int m = node[ri].mid();
        int ans = inf;
        if(rr <= m) {
            ans = min(ans, query(ri << 1, ll, rr));
        }
        else if(ll > m) {
            ans = min(ans, query(ri << 1 | 1, ll, rr));
        }
        else {
            ans = min(ans, query(ri << 1, ll, m));
            ans = min(ans, query(ri << 1 | 1, m + 1, rr));
        }
        return ans;
    }
    
    int main() {
    scanf("%d", &k);
    scanf("%s", ch + 1);
    int len = strlen(ch + 1);
    int val = 0, t = len;
    memset(l, -1, sizeof(l));
    memset(r, -1, sizeof(r));
    for(int i = len; i >= 1; i--) {
        while(val <= k && t > 0) {
            if(num[ch[t] - 'a' ] == 0) val++;
            num[ch[t] - 'a' ]++;
            t--;
        }
        if(val == k + 1) {
            l[i] = t + 2;
        }
        else if(val == k && t == 0) {
            l[i] = t + 1;
        }
        if(num[ch[i] - 'a' ] == 1) val--;
        num[ch[i] - 'a' ]--;
    }
    memset(num, 0, sizeof(num));
    val = 0, t = len;
    for(int i = len; i >= 1; i--) {
        while(val < k && t > 0) {
            if(num[ch[t] - 'a' ] == 0) val++;
            num[ch[t] - 'a' ]++;
            t--;
        }
        if(val == k) {
            r[i] = t + 1;
        }
        if(num[ch[i] - 'a' ] == 1) val--;
        num[ch[i] - 'a' ]--;
    }
    //for(int i = 1; i <= len; i++) {
    //    printf("%d %d
    ", l[i], r[i]);
    //}
    build(1, 0, len);
    int mi = 0;
    for(int i = 1; i <= len; i++) {
    //printf("cac
    ");
        if(l[i] == -1) {
            c[i] = -1;
        }
        else if(l[i] == 1) {
            c[i] = 1;
            update(1, i, 1);
        }
        else {
    //        printf("buics
    ");
    //        int ll ,rr;
    
            mi = query(1, l[i] - 1, r[i] - 1);
            if(mi != inf) {
                c[i] = mi + 1;
                update(1, i, mi + 1);
            }
            else c[i] = -1;
        }
    }
    for(int i = 1; i <= len; i++) {
        printf("%d%c", c[i], i == len ? '
    ': ' ');
    }
    return 0;
    }

     然后这一题还可以用dp做,

    相当于还是尺取去寻找“好字符串”,然后如果i - 1这个点与前面的字符可以组成好字符串的话,就可以用它来更新t这个点一级t后面可以组成好字符串的点,标准的dp思想,用前面的点去更新后面的点。

    #include<bits/stdc++.h>
    
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pii;
    const int inf = 0x3f3f3f3f;
    const int mod = 1e9 + 7;
    const int maxm = 2e5 + 5;
    int k;
    char ch[maxm];
    int dp[maxm];
    int c[maxm];
    int num[30];
    int main() {
    scanf("%d", &k);
    scanf("%s", ch + 1);
    int n = strlen(ch + 1);
    int t = 1, cnt = 0;
    memset(dp, inf, sizeof(dp));
    memset(num, 0, sizeof(num));
    dp[0] = 0;
    for(int i = 1; i <= n; i++) {
        while(t <= n && cnt < k) {
            if(num[ch[t] - 'a' ] == 0) cnt++;
            num[ch[t] - 'a' ]++;
            t++;
        }
        if(cnt == k) {
            if(dp[i - 1] != inf){
                dp[t - 1] = min(dp[t - 1], dp[i - 1] + 1);
    //                if(t == 6) printf("%d %d %d
    ", dp[t], i - 1, dp[i - 1]) ;
                while(t <= n) {
                    if(num[ch[t] - 'a' ] == 0) break;
                    dp[t] = min(dp[i - 1] + 1, dp[t]);
                    num[ch[t]  - 'a']++;
                    t++;
                }
            }
        }
        if(num[ch[i] - 'a' ] == 1) cnt--;
        num[ch[i] - 'a' ]--;
    }
    for(int i = 1; i <= n; i++) {
        printf("%d%c", dp[i] == inf ? -1 : dp[i], i == n ? '
    ' : ' ');
    }
    return 0;
    }

     http://acm.hdu.edu.cn/showproblem.php?pid=6514 吉司机线段树

    https://blog.csdn.net/LSD20164388/article/details/89413657

    题意:

    给你n,m(n,m<=5e5),表示有编号1~n的人,m个区间

    对于每个区间[l,r],表示编号为[l,r]的人之间任意两两配对的方法总数

    要求对于每个区间,输出其任意两两配对的方法总数减去前面的区间已经有的选法总数

    例如[2,5] 可以有 23 24 25 34 35 45      6种

    再给你[4,6] 则只有 46 56 2种(45在上面出现过了)

    思路:

    把这题当图论来想。。。一段区间一定是连续的

    令a[i]=k表示(k,i)(k+1,i)...,(i-1,i)已经被算入答案

    初始化a[i]=i

    对于每次给定的区间[ql,qr],如果max{a[ql],a[ql+1],...,a[qr]}中的最大值<=ql,那么表示区间i属于[ql,qr]中所有(ql,i)的方法总数已经计算过了

    如果max{a[ql],a[ql+1],...,a[qr]}中的最大值>ql 那么就说明至少存在一个i(a[i]>ql)属于[ql,qr],使(ql,i)(ql+1,i),...,(a[i]-1,i)可以被算入答案,然后更新a[i]=ql

    发现上述过程可以用一个线段树维护区间最大值。。。但是因为要计算答案,每次我们必须更新到底。。。(max{a[ql],a[ql+1],...,a[qr]}中的最大值<=ql,那么就可以直接return 0 了,否则继续往下更新)

    在更新的同时统计答案

    这就是传说中的吉司机线段树。。。

    #include<bits/stdc++.h>
    #define ll long long
    #define inf 0x3f3f3f3f
    #define lson  (i<<1)
    #define rson  (i<<1|1)
    #define mid   ((l+r)>>1)
    #define rep(i,a,b) for(register int i=(a);i<=(b);i++)
    #define dep(i,a,b) for(register int i=(a);i>=(b);i--)
    using namespace std;
    const int maxn=500010;
    int n,m,k;
    struct node
    {
        int ma,v;
    }a[maxn<<2];
    void build(int i,int l,int r)
    {
        if(l==r)
        {
            a[i].ma=a[i].v=l;
            return ;
        }
        build(lson,l,mid);
        build(rson,mid+1,r);
        a[i].ma=max(a[lson].ma,a[rson].ma);
    }
    ll update(int i,int l,int r,int ql,int qr,int x)
    {
        ll res=0;
        if(x>=a[i].ma) return res;
        if(l==r)
        {
            res+=a[i].v-x;
            //cout<<i<<" "<<ql<<" "<<qr<<" "<<res<<endl;
            a[i].ma=a[i].v=x;
            return res;
        }
        if(ql<=l&&r<=qr)
        {
            res+=update(lson,l,mid,ql,mid,x);
            res+=update(rson,mid+1,r,mid+1,qr,x);
            a[i].ma=max(a[lson].ma,a[rson].ma);
            return res;
        }
        if(ql<=mid) res+=update(lson,l,mid,ql,min(qr,mid),x);
        if(qr>mid) res+=update(rson,mid+1,r,max(mid+1,ql),qr,x);
        a[i].ma=max(a[lson].ma,a[rson].ma);
        return res;
    }
    int main()
    {
        while(scanf("%d%d",&n,&m)!=EOF)
        {
            build(1,1,n);
            rep(i,1,m)
            {
                int x,y;
                scanf("%d%d",&x,&y);
                printf("%lld
    ",update(1,1,n,x,y,x));
            }
        }
        return 0;
    }

    https://blog.csdn.net/MrBird_to_fly/article/details/77141881  吉司机线段树题目

    http://acm.hdu.edu.cn/showproblem.php?pid=5306   HDU 5306


    0 x y t: For every xiy, we use min(ai,t) to replace the original ai's value.
    1 x y: Print the maximum value of ai that xiy.
    2 x y: Print the sum of ai that xiy.

    case 1:t大于最大值,此时区间不变; 
    case 2:t小于严格次大值,此时至少把最大值和次大值变得相同,即使得区间变得相同,允许暴力更新; 
    case 3:t大于严格次大值,小于最大值,这里可以打懒标记。

    考虑查询,只需维护最大值,最大值个数,严格次大值即可。

    复杂度为nlogn或nlogn2.

    //吉司机宇宙线段树之王!
    #include <bits/stdc++.h>
    using namespace std;
    const int maxn=1000005;
    typedef long long ll;
    
    int mx[maxn<<2];//区间最大值
    int cnt[maxn<<2];//最大值个数
    int se[maxn<<2];//区间严格次小值,就是必须小于最大值
    int lazy[maxn<<2];
    ll sum[maxn<<2];//区间和
    int a[maxn];
    int n, m;
    
    void putlazy(int u, int t){
        sum[u]-=1LL*cnt[u]*(mx[u]-t);
        mx[u]=t;
        lazy[u]=t;
    }
    
    void pushdown(int u){
        if(lazy[u]==-1)return;
        if(mx[2*u]>lazy[u]){
            sum[2*u]-=1LL*cnt[2*u]*(mx[2*u]-lazy[u]);
            mx[2*u]=lazy[u];
            lazy[2*u]=lazy[u];
        }
        if(mx[2*u+1]>lazy[u]){
            sum[2*u+1]-=1LL*cnt[2*u+1]*(mx[2*u+1]-lazy[u]);
            mx[2*u+1]=lazy[u];
            lazy[2*u+1]=lazy[u];
    
        }
        lazy[u]=-1;
    }
    
    void pushup(int u){
        if(mx[2*u]==mx[2*u+1]){
            mx[u]=mx[2*u];
            cnt[u]=cnt[2*u]+cnt[2*u+1];
            se[u]=max(se[2*u], se[2*u+1]);
            sum[u]=sum[2*u]+sum[2*u+1];
        }
        else if(mx[2*u]>mx[2*u+1]){
            mx[u]=mx[2*u];
            cnt[u]=cnt[2*u];
            se[u]=max(se[2*u], mx[2*u+1]);
            sum[u]=sum[2*u]+sum[2*u+1];
        }
        else {
            mx[u]=mx[2*u+1];
            cnt[u]=cnt[2*u+1];
            se[u]=max(mx[2*u], se[2*u+1]);
            sum[u]=sum[2*u]+sum[2*u+1];
        }
    }
    
    void build(int u, int l, int r){
        lazy[u]=-1;
        if(l==r){
            mx[u]=sum[u]=a[l];
            cnt[u]=1;
            se[u]=-1;
            return;
        }
        int mid=(l+r)>>1;
        build(2*u, l, mid);
        build(2*u+1, mid+1, r);
        pushup(u);
    }
    
    void update(int u, int ql, int qr, int t, int l, int r){
        if(mx[u]<=t)return;
        if(ql<=l && r<=qr && se[u] < t){
            putlazy(u, t);
            return;
        }
        if(l == r) return;
        pushdown(u);
        int mid=(l+r)>>1;
        if(qr <= mid) update(u << 1, ql, qr, t, l, mid);
        else if(ql > mid) update(u << 1 | 1, ql, qr, t, mid + 1, r);
        else update(u << 1, ql, mid, t, l, mid), update(u << 1 | 1, mid + 1, qr, t, mid + 1, r);
    //    update(2*u, ql, qr, t, l, mid);
    //    update(2*u+1, ql, qr, t, mid+1, r);
        pushup(u);
    }
    
    int getmx(int u, int ql, int qr, int l, int r){
    //    if(ql>r||qr<l)return 0;
        if(ql<=l&&r<=qr)return mx[u];
        pushdown(u);
        int mid=(l+r)>>1;
        int ans=0;
        if(qr <= mid) ans = max(ans, getmx(u << 1, ql, qr, l, mid));
        else if(ql > mid) ans = max(ans, getmx(u << 1 | 1, ql, qr, mid + 1, r));
        else {
            ans = max(ans, getmx(u << 1, ql, mid, l, mid));
            ans = max(ans, getmx(u << 1 | 1, mid + 1, qr, mid + 1, r));
        }
    //    ans=max(ans, getmx(2*u, ql, qr, l, mid));
    //    ans=max(ans, getmx(2*u+1, ql, qr, mid+1, r));
        return ans;
    }
    
    ll getsum(int u, int ql, int qr, int l, int r){
    //    if(ql>r||qr<l)return 0;
        if(ql<=l&&r<=qr)return sum[u];
        pushdown(u);
        int mid=(l+r)>>1;
        ll ans=0;
        if(qr <= mid) ans += getsum(u << 1, ql, qr, l, mid);
        else if(ql > mid) ans += getsum(u << 1 | 1, ql, qr, mid + 1, r);
        else {
            ans += getsum(u << 1, ql, mid, l, mid);
            ans += getsum(u << 1 | 1, mid + 1, qr, mid + 1, r);
        }
    //    ans+=getsum(2*u, ql, qr, l, mid);
    //    ans+=getsum(2*u+1, ql, qr, mid+1, r);
        return ans;
    }
    
    int main(){
        int T;
        scanf("%d", &T);
        while(T--){
            scanf("%d%d", &n, &m);
            for(int i=1;i<=n;i++)scanf("%d", &a[i]);
            build(1, 1, n);
            for(int i=1;i<=m;i++){
                int tag;
                scanf("%d", &tag);
                if(tag==0){
                    int x, y, t;
                    scanf("%d%d%d", &x, &y, &t);
                    update(1, x, y, t, 1, n);
                }
                else if(tag==1){
                    int x, y;
                    scanf("%d%d", &x, &y);
                    printf("%d
    ", getmx(1, x, y, 1, n));
                }
                else {
                    int x, y;
                    scanf("%d%d", &x, &y);
                    printf("%lld
    ", getsum(1, x, y, 1, n));
                }
            }
        }
    }

    https://www.cnblogs.com/GXZlegend/p/8349722.html

    https://www.lydsy.com/JudgeOnline/status.php?user_id=downrainsun 提交的地方。

    维护一个长度为N的序列a,现在有三种操作:
    1)给出参数U,V,C,将a[U],a[U+1],...,a[V-1],a[V]都赋值为C。
    2)给出参数U,V,C,对于区间[U,V]里的每个数i,将a[i]赋值为max(a[i]+C,0)。
    3)给出参数U,V,输出a[U],a[U+1],...,a[V-1],a[V]里值为0的数字个数。

    Input

    第一行包含两个正整数N,M(1<=N,M<=300000),分别表示序列长度和操作个数。
    第二行包含N个整数,其中第i个数表示a[i](0<=a[i]<=10^9),描述序列的初始状态。
    接下来M行描述M个操作,保证1<=U<=V<=N,对于操作1,0<=C<=10^9,对于操作2,|C|<=10^9。
    //吉司机线段树
    //牛逼啊
    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int maxn=300005;
    
    int n, m;
    ll mn[maxn<<2];
    int cnt[maxn<<2];
    ll se[maxn<<2];
    ll lzcut[maxn<<2];
    ll lzadd[maxn<<2];
    int a[maxn];
    
    void putcut(int u, ll c){
        mn[u]=c;
        lzcut[u]=c;
    }
    
    void putadd(int u, ll c){
        lzadd[u]+=c;
        if(lzcut[u]!=-1)lzcut[u]+=c;
        mn[u]+=c;
        if(se[u]!=-1)se[u]+=c;
    }
    
    void pushdown(int u){
        if(lzadd[u]){
            putadd(2*u, lzadd[u]);
            putadd(2*u+1, lzadd[u]);
            lzadd[u]=0;
        }
        if(lzcut[u]!=-1){
            if(mn[2*u]<lzcut[u]){
                mn[2*u]=lzcut[u];
                lzcut[2*u]=lzcut[u];
            }
            if(mn[2*u+1]<lzcut[u]){
                mn[2*u+1]=lzcut[u];
                lzcut[2*u+1]=lzcut[u];
            }
            lzcut[u]=-1;
        }
    }
    
    void pushup(int u){
        if(mn[2*u]==mn[2*u+1]){
            mn[u]=mn[2*u];
            cnt[u]=cnt[2*u]+cnt[2*u+1];
            if(se[2*u]==-1&&se[2*u+1]==-1)se[u]=-1;
            else if(se[2*u]==-1)se[u]=se[2*u+1];
            else if(se[2*u+1]==-1)se[u]=se[2*u];
            else se[u]=min(se[2*u], se[2*u+1]);
        }
        else if(mn[2*u]<mn[2*u+1]){
            mn[u]=mn[2*u];
            cnt[u]=cnt[2*u];
            if(se[2*u]==-1){
                se[u]=mn[2*u+1];
            }
            else {
                se[u]=min(mn[2*u+1], se[2*u]);
            }
        }
        else {
            mn[u]=mn[2*u+1];
            cnt[u]=cnt[2*u+1];
            if(se[2*u+1]==-1){
                se[u]=mn[2*u];
            }
            else {
                se[u]=min(mn[2*u], se[2*u+1]);
            }
        }
    }
    
    void build(int u, int l, int r){
        lzcut[u]=-1;
        lzadd[u]=0;
        if(l==r){
            mn[u]=a[l];
            cnt[u]=1;
            se[u]=-1;
            return;
        }
        int mid=(l+r)/2;
        build(2*u, l, mid);
        build(2*u+1, mid+1, r);
        pushup(u);
    }
    
    void cover(int u, int ql, int qr, int c, int l, int r){
        if(r<ql||qr<l)return;
        if(ql<=l&&r<=qr&&se[u]==-1){
            putadd(u, (ll)c-mn[u]);
            return;
        }
        int mid=(l+r)/2;
        pushdown(u);
        cover(2*u, ql, qr, c, l, mid);
        cover(2*u+1, ql, qr, c, mid+1, r);
        pushup(u);
    }
    
    void add(int u, int ql, int qr, int c, int l, int r){
        if(r<ql||qr<l||(se[u]==-1&&mn[u]==0&&c<=0))return;
        if(ql<=l&&r<=qr){
            if(mn[u]+c>=0){
                putadd(u, c);
                return;
            }
            else if(se[u]==-1||se[u]+c>0){
                putadd(u, c);
                putcut(u, 0);
                return;
            }
        }
        int mid=(l+r)/2;
        pushdown(u);
        add(2*u, ql, qr, c, l, mid);
        add(2*u+1, ql, qr, c, mid+1, r);
        pushup(u);
    }
    
    int query(int u, int ql, int qr, int l, int r){
        if(r<ql||qr<l)return 0;
        if(ql<=l&&r<=qr){
            if(mn[u]==0)return cnt[u];
            return 0;
        }
        int mid=(l+r)/2;
        int ret=0;
        pushdown(u);
        ret+=query(2*u, ql, qr, l, mid);
        ret+=query(2*u+1, ql, qr, mid+1, r);
        return ret;
    }
    
    
    int main(){
        scanf("%d%d", &n, &m);
        for(int i=1;i<=n;i++){
            scanf("%d", &a[i]);
        }
        build(1, 1, n);
        for(int i=1;i<=m;i++){
            int tag;
            scanf("%d", &tag);
            if(tag==1){
                int l, r, c;
                scanf("%d%d%d", &l, &r, &c);
                cover(1, l, r, c, 1, n);
            }
            else if(tag==2){
                int l, r, c;
                scanf("%d%d%d", &l, &r, &c);
                add(1, l, r, c, 1, n);
            }
            else {
                int l, r;
                scanf("%d%d", &l, &r);
                printf("%d
    ", query(1, l, r, 1, n));
            }
        }
    }

    http://codeforces.com/contest/1199/problem/D

    一串序列,两种操作,第一种把某个点的值改为某个值,第二种:把一个区间内小于x的数全部改为x.

    这一题正解并不是线段树。

    线段树做法:lazy标记,mi最小值数组,cnt表示值。

    #include<bits/stdc++.h>
    
    using namespace std;
    typedef long long ll;
    const int N = 2e5 + 5;
    ll cnt[N << 2];
    ll lazy[N << 2];
    ll mi[N << 2];
    
    void push_down(int rt) {
        if(lazy[rt] != -1) {
            if(mi[rt << 1] < mi[rt]) {
                mi[rt << 1] = mi[rt];
                lazy[rt << 1] = lazy[rt];
            }
            if(mi[rt << 1 | 1] < mi[rt]) {
                mi[rt << 1 | 1] = mi[rt];
                lazy[rt << 1 | 1] = lazy[rt];
            }
            lazy[rt] = -1;
        }
    }
    
    void pushup(int rt) {
        mi[rt] = min(mi[rt << 1], mi[rt << 1 | 1]);
    }
    
    int n;
    void print(int rt, int l, int r) {
        if(l == r) {
            printf("%I64d%c", max(cnt[rt], mi[rt]), l == n ? '
    ' : ' ');
            return;
        }
        push_down(rt);
        int m = (l + r) >> 1;
        print(rt << 1, l, m);
        print(rt << 1 | 1, m + 1, r);
    }
    
    void build(int rt, int l, int r) {
        if(l == r) {
            scanf("%I64d", &cnt[rt]), lazy[rt] = -1, mi[rt] = cnt[rt];
            return;
        }
    //    push_down(rt);
        int m = (l + r) >> 1;
        build(rt << 1, l, m);
        build(rt << 1 | 1, m + 1, r);
        pushup(rt);
    }
    
    void update1(int rt, int l ,int r, int pos, ll val) {
        if(l == r) {
            cnt[rt] = val;
            mi[rt] = val;
            return;
        }
        push_down(rt);
        int m = (l + r) >> 1;
        if(pos <= m) update1(rt << 1, l, m, pos, val);
        else update1(rt << 1 | 1, m + 1, r, pos, val);
        pushup(rt);
    }
    
    //void update2(int rt, int l, int r, ll val) {
    //    if(mi[rt] >= val) return;
    //    else {
    //        mi[rt] = val;
    //        lazy[rt] = val;
    //        return;
    //    }
    ////    push_down(rt);
    ////    int m = (l + r) >> 1;
    ////    update2(rt << 1, l, m, val);
    ////    update2(rt << 1 | 1, m + 1, r, val);
    ////    pushup(rt);
    //}
    
    int main() {
        scanf("%d", &n);
        build(1, 1, n);
        int q;
        scanf("%d", &q);
        int opt, x;
        ll y;
        while(q--) {
            scanf("%d", &opt);
            if(opt == 1) {
                scanf("%d%I64d", &x, &y);
                update1(1, 1, n, x, y);
            }
            else {
                scanf("%I64d", &y);
                if(mi[1] < y) {
                    mi[1] = y;
                    lazy[1] = y;
                }
    //            update2(1, 1, n, y);
            }
        }
        print(1, 1, n);
        return 0;
    }

    https://ac.nowcoder.com/acm/contest/888/E

    线段树,叶子节点表示区间。

    这个题是给你一个图,每条边有一个允许通过的体型范围,然后要从一号节点到n号节点,要求可以通过的体型值有多少个。

    线段树+按秩合并并查集

    https://blog.csdn.net/qq_41117236/article/details/99179573

    对于每个原始区间的l与r,存为l与r + 1,并放入一个数组中去重排序,最后找区间的时候起点lower_bound找起点区间,重点lower_bound找到后还要减一,因为终点所代表的区间并不在这个范围内,

    那么然后叶子节点代表的区间就是q[l + 1] - q[l]。

    #include<bits/stdc++.h>
    using namespace std;
    typedef pair<int,int> P;
    const int N=1e5+10;
    struct edge{ //
        int u,v,l,r;
    }f[N];
    int pre[N],rk[N]; //pre[]表示父节点,rk[]表示并查集的秩
    int q[N<<1];
    vector <P> a[N<<3]; //线段树
    vector <int> t[30];
    P V;
    int n,m,ans;
    void build(int x,int l,int r,int fl,int fr)
    {
        if(l==fl&&r==fr){
    //        printf("%d %d
    ", l, r);
            a[x].push_back(V);
            return;
        }
        int mid=(l+r)>>1;
        if(fr<=mid) build(x<<1,l,mid,fl,fr);
        else if(fl>mid) build(x<<1|1,mid + 1,r,fl,fr);
        else build(x<<1,l,mid,fl,mid),build(x<<1|1,mid + 1,r,mid + 1,fr);
    }
    int Find(int x)
    {
        return pre[x]==x?x:Find(pre[x]);
    }
    void join(int rt,int x,int y,int dep)
    {
        x=Find(x),y=Find(y);
        if(x!=y){
            if(rk[x]<=rk[y]){ //按秩合并
                pre[x]=y,t[dep].push_back(x);
                if(rk[x]==rk[y]) rk[y]++;
            }
            else{
                pre[y]=x,t[dep].push_back(y);
            }
        }
    }
    int cnt;
    void dfs(int x,int l,int r,int dep) //x表示节点编号,dep表示节点深度
    {
        t[dep].clear();
        for(int i = 0; i < a[x].size(); i++) join(x,a[x][i].first,a[x][i].second,dep);
    //    printf("%d
    ", dep);
        if(l==r){
    //        printf("%d %d
    ", l, r);
            if(Find(1)==Find(n)) ans+=q[r + 1]-q[l]; //更新贡献
    //        for(auto i:t[dep]) pre[i]=i;
            for(int i = 0; i < t[dep].size(); i++) pre[t[dep][i] ] = t[dep][i];
            return;
        }
        int mid=(l+r)>>1;
        dfs(x<<1,l,mid,dep+1);
        dfs(x<<1|1,mid + 1,r,dep+1);
        for(int i = 0; i < t[dep].size(); i++) pre[t[dep][i] ] = t[dep][i];
    //    for(auto i:t[dep]) pre[i]=i;
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        cnt=0;
        for(int i=1;i<=n;i++) pre[i]=i;
        for(int i=1;i<=m;i++){
            scanf("%d%d%d%d",&f[i].u,&f[i].v,&f[i].l,&f[i].r);
            q[++cnt]=f[i].l; q[++cnt]=f[i].r + 1;
        }
        sort(q+1,q+cnt+1); //把区间排序进行离散化
        cnt=unique(q+1,q+cnt+1)-q-1;
        for(int i=1;i<=m;i++){
            V=P(f[i].u,f[i].v);
            int p1=lower_bound(q+1,q+cnt+1,f[i].l)-q;
            int p2=lower_bound(q+1,q+cnt+1,f[i].r+1)-q - 1;
            build(1,1,cnt - 1,p1,p2); //以区间为关键字建树
        }
        ans=0;
    //    printf("%d
    ", cnt);
        dfs(1,1,cnt - 1,1); //从根1向下dfs
        printf("%d
    ",ans);
        return 0;
    }
  • 相关阅读:
    115. 不同的子序列
    114. 二叉树展开为链表
    基于Docker结合Canal实现MySQL实时增量数据传输
    Docker-Compose
    Docker容器的创建、启动、和停止
    ES集群
    ES
    Docker配置JDK1.8镜像
    Docker及Docker-Compose的使用
    docker安装jdk
  • 原文地址:https://www.cnblogs.com/downrainsun/p/10355710.html
Copyright © 2020-2023  润新知