线段树专辑

来源:互联网 发布:大数据龙头公司 编辑:程序博客网 时间:2024/05/22 12:10

代码风格:

  • maxn是题目给的最大区间,而节点数要开4倍,确切的来说节点数要开大于maxn的最小2x的两倍
  • lson和rson分辨表示结点的左儿子和右儿子,由于每次传参数的时候都固定是这几个变量,所以可以用预定于比较方便的表示
  • 以前的写法是另外开两个个数组记录每个结点所表示的区间,其实这个区间不必保存,一边算一边传下去就行,只需要写函数的时候多两个参数,结合lson和rson的预定义可以很方便
  • PushUP(int rt)是把当前结点的信息更新到父结点
  • PushDown(int rt)是把当前结点的信息更新给儿子结点
  • rt表示当前子树的根(root),也就是当前所在的结点


hdu 1166

线段树功能:update:单点增减 query:区间求和

#include<stdio.h>#include<string.h>#include<stdlib.h>#define lson l , m , rt << 1#define rson m+1 , r , rt << 1 | 1const int maxn = 55555;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){    int m;    if(l == r)    {        scanf("%d",&sum[rt]);        return ;    }    m = (l + r) >> 1;    build(lson);    build(rson);    PushUP(rt);}void update(int p,int add,int l,int r,int rt){    int m;    if(l == r)    {        sum[rt] += add;        return ;    }    m = (l + r) >> 1;    if(p <= m) update(p,add,lson);    else update(p,add,rson);    PushUP(rt);}int query(int L,int R,int l,int r,int rt){    int m,ret;    if(L <= l && r<=R)        return sum[rt];    m = (l + r) >> 1;    ret = 0;    if(L <= m) ret += query(L,R,lson);    if(R > m) ret += query(L,R,rson);    return ret;}int main(){    int T,n,ncase,a,b;    char op[10];    scanf("%d",&T);    for(ncase=1;ncase<=T;ncase++)    {        scanf("%d",&n);        build(1,n,1);        printf("Case %d:\n",ncase);        while(scanf("%s",&op))        {            if(op[0] == 'E') break;            scanf("%d%d",&a,&b);            if(op[0] == 'Q')                printf("%d\n",query(a,b,1,n,1));            else if(op[0] == 'S')                update(a,-b,1,n,1);            else                update(a,b,1,n,1);        }    }    return 0;}

hdu 1754  I hate it

#include<stdio.h>#include<string.h>#include<stdlib.h>#define lson l , m , rt<<1#define rson m+1 , r , rt<<1|1const int MAXN = 200010;int sum[MAXN<<2];int max(int a,int b){    return a > b ? a : b;}void PushUP(int rt){    sum[rt] = max(sum[rt<<1] , sum[rt<<1|1]);}void build(int l,int r,int rt){    int m;    if(l == r)    {        scanf("%d",&sum[rt]);        return ;    }    m = (l + r) >> 1;    build(lson);    build(rson);    PushUP(rt);}int query(int L,int R,int l,int r,int rt){    int m,ans = 0;    if(L <= l && r <= R)    {        return sum[rt];    }    m = (l + r) >> 1;    if(L <= m) ans = max(ans,query(L,R,lson));    if(R > m) ans = max(ans,query(L,R,rson));    return ans;}void update(int pos,int value,int l,int r,int rt){    int m;    if(l == r)    {        sum[rt] = value;        return ;    }    m = (l + r) >> 1;    if(pos <= m)        update(pos,value,lson);    else        update(pos,value,rson);    PushUP(rt);}int main(){    int N,M,a,b,i;    char op;    while(~scanf("%d%d",&N,&M))    {        build(1,N,1);        getchar();        for(i = 0;i < M;i ++)        {            scanf("%c %d %d",&op,&a,&b);            if(op == 'Q')                printf("%d\n",query(a,b,1,N,1));            else                update(a,b,1,N,1);            getchar();        }    }    return 0;}

hdu 1394

题意:求Inversion后的最小逆序数
思路:用O(nlogn)复杂度求出最初逆序数后,就可以用O(1)的复杂度分别递推出其他解
线段树功能:update:单点增减 query:区间求和

#include<stdio.h>#include<string.h>#include<stdlib.h>#define lson l , m , rt << 1#define rson m+1 , r , rt << 1 | 1const 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){    int m;    if(l == r)    {        sum[rt] = 0;        return ;    }    m = (l + r) >> 1;    build(lson);    build(rson);    PushUP(rt);}int query(int L,int R,int l,int r,int rt){    int m,ans = 0;    if(L <= l && r <= R)        return sum[rt];    m = (l + r) >> 1;    if(L <= m) ans += query(L,R,lson);    if(R > m) ans += query(L,R,rson);    return ans;}void update(int pos,int value,int l,int r,int rt){    int m;    if(l == r)    {        sum[rt] = value;        return ;    }    m = (l + r) >> 1;    if(pos <= m)        update(pos,value,lson);    else        update(pos,value,rson);    PushUP(rt);}int min(int a,int b){    return a > b ? b : a;}int x[maxn];int main(){    int n,i,sum,ans;    while(~scanf("%d",&n))    {        sum = 0;        build(1,n,1);        for(i = 0;i < n;i ++)        {            scanf("%d",&x[i]);            sum += query(x[i] + 1,n,1,n,1);            update(x[i] + 1,1,1,n,1);        }        ans = 10000000;        for(i = 0;i < n;i ++)        {            sum += n - x[i] - x[i] -1;            ans = min(sum,ans);        }        printf("%d\n",ans);    }    return 0;}

hdu 2795

这题有点DT,一开始我以为是一个复杂的DP,但是其实不是 == ,只要每次找到最大值的位子,然后减去L就可以了 =。=

比如,对于输入:

2 6 4

3/2/4/3

输出为:

1/1/2/-1,

而不是2/1/1/2   =。=

只是个贪心 = =

# include <stdio.h>#define lson l,m,rt << 1#define rson m + 1,r,rt << 1|1const int maxn = 200010;int MAX[maxn<<2];int h,w,n;int max(int a,int b){    return a > b ? a : b;}void PushUP(int rt){    MAX[rt] = max(MAX[rt << 1],MAX[rt << 1|1]);}void build(int l,int r,int rt){    int m;    if(l == r)    {        MAX[rt] = w;        return ;    }    m = (l + r) >> 1;    build(lson);    build(rson);    PushUP(rt);}int query(int x,int l,int r,int rt){    int m,ans;    if(l == r)    {        MAX[rt] -= x;        return l;    }    m = (l + r) >> 1;    ans = (MAX[rt << 1] >= x) ? query(x,lson) : query(x,rson);    PushUP(rt);    return ans;}int main(){    int i,x;    while(~scanf("%d%d%d",&h,&w,&n))    {        if(h > n) h = n;        build(1,h,1);        for(i = 0;i < n;i ++)        {            scanf("%d",&x);            if(x > MAX[1])                puts("-1");            else                printf("%d\n",query(x,1,h,1));        }    }    return 0;}

poj 2828

给定n个人进入队伍时的位置,如果某个位置及其后面有人,则后面的人都要向后挪一个位置,这不正是每天都在现实生活中上演的插队问题吗!有n个pos[i]和val[i],pos[i]表示这个人插入到pos[i]的右面,其实加1的话,更好理解,就是插在什么位置。至于那个val[i]只是为了表示某个人而已,理解成RP什么的都可以。


换个角度,后插进来的人更容易定位,比如最后一个人插在什么位置就是在什么位置,不需要挪动,这也很容易理解。现在从后面开始定位每个人的位置,不失一般性,如果某个人插入到pos[i],则找第pos[i]个空位置插入即可,记录空位置可以通过线段树实现


# include <stdio.h>#define lson l , m , rt<<1#define rson m+1 , r , rt<<1|1const int maxn = 200010;int empty[maxn<<2];int ans[maxn],pos[maxn],val[maxn];int index;void build(int l,int r,int rt){    int m;    empty[rt] = r - l + 1;    if(l == r)        return ;    m = (l + r) >> 1;    build(lson);    build(rson);}void update(int p,int l,int r,int rt){    int m;    empty[rt] --;    if(l == r)    {        index = l;        return ;    }    m = (l + r) >> 1;    if(empty[rt<<1] >= p)        update(p,lson);    else        p -= empty[rt<<1],update(p,rson);}int main(){    int n,i;    while(~scanf("%d",&n))    {        build(1,n,1);        for(i = 1;i <= n;i ++)            scanf("%d%d",&pos[i],&val[i]);        for(i = n;i >= 1;i --)            update(pos[i]+1,1,n,1),ans[index] = val[i];        for (i = 1; i <= n; ++i)            printf(i == n ? "%d\n" : "%d ",ans[i]);    }    return 0;}


原创粉丝点击