线段树

注:我在修炼当中,博客完全是为了自己复习方便看得,如果你不慎点入了我的博客,看看就好,不要相信,误人子弟就不好了- -

模板是从别人那借鉴来的,暂时放在这

模板一

RMQ,查询区间最值下标—min

#include<iostream>

using namespace std;

#define MAXN 100
#define MAXIND 256 //线段树节点个数 

//构建线段树,目的:得到M数组.
void build(int node, int b, int e, int M[], int A[])
{
    if (b == e)
        M[node] = b; //只有一个元素,只有一个下标
    else
    {
        build(2 * node, b, (b + e) / 2, M, A);
        build(2 * node + 1, (b + e) / 2 + 1, e, M, A);

        if (A[M[2 * node]] <= A[M[2 * node + 1]])
            M[node] = M[2 * node];
        else
            M[node] = M[2 * node + 1];
    }
}

//找出区间 [i, j] 上的最小值的索引
int query(int node, int b, int e, int M[], int A[], int i, int j)
{
    int p1, p2;

    //查询区间和要求的区间没有交集
    if (i > e || j < b)
        return -1;

    if (b >= i && e <= j)
        return M[node];

    p1 = query(2 * node, b, (b + e) / 2, M, A, i, j);
    p2 = query(2 * node + 1, (b + e) / 2 + 1, e, M, A, i, j);

    //return the position where the overall
    //minimum is
    if (p1 == -1)
        return M[node] = p2;
    if (p2 == -1)
        return M[node] = p1;
    if (A[p1] <= A[p2])
        return M[node] = p1;
    return M[node] = p2;

}


int main()
{
    int M[MAXIND]; //下标1起才有意义,否则不是二叉树,保存下标编号节点对应区间最小值的下标.
    memset(M,-1,sizeof(M));
    int a[]= {3,4,5,7,2,1,0,3,4,5};
    build(1, 0, sizeof(a)/sizeof(a[0])-1, M, a);
    cout<<query(1, 0, sizeof(a)/sizeof(a[0])-1, M, a, 0, 5)<<endl;
    return 0;
}

模板二

连续区间修改或者单节点更新的动态查询问题 (此模板查询区间和)

#include <cstdio> 
#include <algorithm> 
using namespace std;    

#define lson l , m , rt << 1 
#define rson m + 1 , r , rt << 1 | 1 
#define root 1 , N , 1 
#define LL long long 
const int maxn = 111111;    
LL add[maxn<<2];    
LL sum[maxn<<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 build(int l,int r,int rt) {    
    add[rt] = 0;    
    if (l == r) {    
        scanf("%lld",&sum[rt]);    
        return ;    
    }    
    int m = (l + r) >> 1;    
    build(lson);    
    build(rson);    
    PushUp(rt);    
}    
void update(int L,int R,int c,int l,int r,int rt) {    
    if (L <= l && r <= R) {    
        add[rt] += c;    
        sum[rt] += (LL)c * (r - l + 1);    
        return ;    
    }    
    PushDown(rt , r - l + 1);    
    int m = (l + r) >> 1;    
    if (L <= m) update(L , R , c , lson);    
    if (m < R) update(L , R , c , rson);    
    PushUp(rt);    
}    
LL query(int L,int R,int l,int r,int rt) {    
    if (L <= l && r <= R) {    
        return sum[rt];    
    }    
    PushDown(rt , r - l + 1);    
    int m = (l + r) >> 1;    
    LL ret = 0;    
    if (L <= m) ret += query(L , R , lson);    
    if (m < R) ret += query(L , R , rson);    
    return ret;    
}    
int main() {    
    int N , Q;    
    scanf("%d%d",&N,&Q);    
    build(root);    
    while (Q --) {    
        char op[2];    
        int a , b , c;    
        scanf("%s",op);    
        if (op[0] == 'Q') {    
            scanf("%d%d",&a,&b);    
            printf("%lld\n",query(a , b ,root));    
        } else {    
            scanf("%d%d%d",&a,&b,&c);    
            update(a , b , c , root);    
        }    
    }    
    return 0;    
}  

模板三

最小逆序数 HDU1394

#include <cstdio> 
#include <algorithm> 
using namespace std;  

#define lson l , m , rt << 1 
#define rson m + 1 , r , rt << 1 | 1 
const int maxn = 5555;  
int sum[maxn<<2];  
void PushUP(int rt) {  
    sum[rt] = sum[rt<<1] + sum[rt<<1|1];  
}  
void build(int l,int r,int rt) {  
    sum[rt] = 0;  
    if (l == r) return ;  
    int m = (l + r) >> 1;  
    build(lson);  
    build(rson);  
}  
void update(int p,int l,int r,int rt) {  
    if (l == r) {  
        sum[rt] ++;  
        return ;  
    }  
    int m = (l + r) >> 1;  
    if (p <= m) update(p , lson);  
    else update(p , rson);  
    PushUP(rt);  
}  
int query(int L,int R,int l,int r,int rt) {  
    if (L <= l && r <= R) {  
        return sum[rt];  
    }  
    int m = (l + r) >> 1;  
    int ret = 0;  
    if (L <= m) ret += query(L , R , lson);  
    if (R > m) ret += query(L , R , rson);  
    return ret;  
}  
int x[maxn];  
int main() {  
    int n;  
    while (~scanf("%d",&n)) {  
        build(0 , n - 1 , 1);  
        int sum = 0;  
        for (int i = 0 ; i < n ; i ++) {  
            scanf("%d",&x[i]);  
            sum += query(x[i] , n - 1 , 0 , n - 1 , 1);  
            update(x[i] , 0 , n - 1 , 1);  
        }  
        int ret = sum;  
        for (int i = 0 ; i < n ; i ++) {  
            sum += n - x[i] - x[i] - 1;  
            ret = min(ret , sum);  
        }  
        printf("%d\n",ret);  
    }  
    return 0;  
}

模板四

成段更新

#include <cstdio> 
#include <algorithm> 
using namespace std;  

#define lson l , m , rt << 1 
#define rson m + 1 , r , rt << 1 | 1 
#define LL long long 
const int maxn = 111111;  
LL add[maxn<<2];  
LL sum[maxn<<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 build(int l,int r,int rt) {  
    add[rt] = 0;  
    if (l == r) {  
        scanf("%lld",&sum[rt]);  
        return ;  
    }  
    int m = (l + r) >> 1;  
    build(lson);  
    build(rson);  
    PushUp(rt);  
}  
void update(int L,int R,int c,int l,int r,int rt) {  
    if (L <= l && r <= R) {  
        add[rt] += c;  
        sum[rt] += (LL)c * (r - l + 1);  
        return ;  
    }  
    PushDown(rt , r - l + 1);  
    int m = (l + r) >> 1;  
    if (L <= m) update(L , R , c , lson);  
    if (m < R) update(L , R , c , rson);  
    PushUp(rt);  
}  
LL query(int L,int R,int l,int r,int rt) {  
    if (L <= l && r <= R) {  
        return sum[rt];  
    }  
    PushDown(rt , r - l + 1);  
    int m = (l + r) >> 1;  
    LL ret = 0;  
    if (L <= m) ret += query(L , R , lson);  
    if (m < R) ret += query(L , R , rson);  
    return ret;  
}  
int main() {  
    int N , Q;  
    scanf("%d%d",&N,&Q);  
    build(1 , N , 1);  
    while (Q --) {  
        char op[2];  
        int a , b , c;  
        scanf("%s",op);  
        if (op[0] == 'Q') {  
            scanf("%d%d",&a,&b);  
            printf("%lld\n",query(a , b , 1 , N , 1));  
        } else {  
            scanf("%d%d%d",&a,&b,&c);  
            update(a , b , c , 1 , N , 1);  
        }  
    }  
    return 0;  
}  

模版五

区间合并

#include <cstdio>
#include <cstring>
#include <cctype>
#include <algorithm>
using namespace std;
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1

const int maxn = 55555;
int lsum[maxn<<2] , rsum[maxn<<2] , msum[maxn<<2];
int cover[maxn<<2];

void PushDown(int rt,int m)
{
    if (cover[rt] != -1)
    {
        cover[rt<<1] = cover[rt<<1|1] = cover[rt];
        msum[rt<<1] = lsum[rt<<1] = rsum[rt<<1] = cover[rt] ? 0 : m - (m >> 1);
        msum[rt<<1|1] = lsum[rt<<1|1] = rsum[rt<<1|1] = cover[rt] ? 0 : (m >> 1);
        cover[rt] = -1;
    }
}
void PushUp(int rt,int m)
{
    lsum[rt] = lsum[rt<<1];
    rsum[rt] = rsum[rt<<1|1];
    if (lsum[rt] == m - (m >> 1)) lsum[rt] += lsum[rt<<1|1];
    if (rsum[rt] == (m >> 1)) rsum[rt] += rsum[rt<<1];
    msum[rt] = max(lsum[rt<<1|1] + rsum[rt<<1] , max(msum[rt<<1] , msum[rt<<1|1]));
}
void build(int l,int r,int rt)
{
    msum[rt] = lsum[rt] = rsum[rt] = r - l + 1;
    cover[rt] = -1;
    if (l == r) return ;
    int m = (l + r) >> 1;
    build(lson);
    build(rson);
}
void update(int L,int R,int c,int l,int r,int rt)
{
    if (L <= l && r <= R)
    {
        msum[rt] = lsum[rt] = rsum[rt] = c ? 0 : r - l + 1;
        cover[rt] = c;
        return ;
    }
    PushDown(rt , r - l + 1);
    int m = (l + r) >> 1;
    if (L <= m) update(L , R , c , lson);
    if (m < R) update(L , R , c , rson);
    PushUp(rt , r - l + 1);
}
int query(int w,int l,int r,int rt)
{
    if (l == r) return l;
    PushDown(rt , r - l + 1);
    int m = (l + r) >> 1;
    if (msum[rt<<1] >= w) return query(w , lson);
    else if (rsum[rt<<1] + lsum[rt<<1|1] >= w) return m - rsum[rt<<1] + 1;
    return query(w , rson);
}
int main()
{
    int n , m;
    scanf("%d%d",&n,&m);
    build(1 , n , 1);
    while (m --)
    {
        int op , a , b;
        scanf("%d",&op);
        if (op == 1)
        {
            scanf("%d",&a);
            if (msum[1] < a) puts("0");
            else
            {
                int p = query(a , 1 , n , 1);
                printf("%d\n",p);
                update(p , p + a - 1 , 1 , 1 , n , 1);
            }
        }
        else
        {
            scanf("%d%d",&a,&b);
            update(a , a + b - 1 , 0 , 1 , n , 1);
        }
    }
    return 0;
}

扫描线

HDU1542

题意:矩形周长并

思路:与面积不同的地方是还要记录竖的边有几个(numseg记录),并且当边界重合的时候需要合并(用lbd和rbd表示边界来辅助)
线段树操作:update:区间增减 query:直接取根节点的值

#define lson l , m , rt << 1 
#define rson m + 1 , r , rt << 1 | 1 

const int maxn = 2222;  
int cnt[maxn << 2];  
double sum[maxn << 2];  
double X[maxn];  
struct Seg {  
    double h , l , r;  
    int s;  
    Seg(){}  
    Seg(double a,double b,double c,int d) : l(a) , r(b) , h(c) , s(d) {}  
    bool operator < (const Seg &cmp) const {  
        return h < cmp.h;  
    }  
}ss[maxn];  
void PushUp(int rt,int l,int r) {  
    if (cnt[rt]) sum[rt] = X[r+1] - X[l];  
    else if (l == r) sum[rt] = 0;  
    else sum[rt] = sum[rt<<1] + sum[rt<<1|1];  
}  
void update(int L,int R,int c,int l,int r,int rt) {  
    if (L <= l && r <= R) {  
        cnt[rt] += c;  
        PushUp(rt , l , r);  
        return ;  
    }  
    int m = (l + r) >> 1;  
    if (L <= m) update(L , R , c , lson);  
    if (m < R) update(L , R , c , rson);  
    PushUp(rt , l , r);  
}  
int Bin(double key,int n,double X[]) {  
    int l = 0 , r = n - 1;  
    while (l <= r) {  
        int m = (l + r) >> 1;  
        if (X[m] == key) return m;  
        if (X[m] < key) l = m + 1;  
        else r = m - 1;  
    }  
    return -1;  
}  
int main() {  
    int n , cas = 1;  
    while (~scanf("%d",&n) && n) {  
        int m = 0;  
        while (n --) {  
            double a , b , c , d;  
            scanf("%lf%lf%lf%lf",&a,&b,&c,&d);  
            X[m] = a;  
            ss[m++] = Seg(a , c , b , 1);  
            X[m] = c;  
            ss[m++] = Seg(a , c , d , -1);  
        }  
        sort(X , X + m);  
        sort(ss , ss + m);  
        int k = 1;  
        for (int i = 1 ; i < m ; i ++) {  
            if (X[i] != X[i-1]) X[k++] = X[i];  
        }  
        memset(cnt , 0 , sizeof(cnt));  
        memset(sum , 0 , sizeof(sum));  
        double ret = 0;  
        for (int i = 0 ; i < m - 1 ; i ++) {  
            int l = Bin(ss[i].l , k , X);  
            int r = Bin(ss[i].r , k , X) - 1;  
            if (l <= r) update(l , r , ss[i].s , 0 , k - 1, 1);  
            ret += sum[1] * (ss[i+1].h - ss[i].h);  
        }  
        printf("Test case #%d\nTotal explored area: %.2lf\n\n",cas++ , ret);  
    }  
    return 0;  
} 

你可能感兴趣的:(线段树)