线段树(堆式)[单点更新, 区间查询]

原创 2012年03月25日 18:59:53


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

first blood of seg-tree  单点增减 区间求和

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int maxn=60000+123;
int T[maxn*2];
int M;

int bit(int x)/// get highest 1 in bit-number
{
    if(x==0)return 0;
    int n=1;
    if((x>>16)==0){n+=16; x<<=16;}
    if((x>>24)==0){n+=8; x<<=8;}
    if((x>>28)==0){n+=4; x<<=4;}
    if((x>>30)==0){n+=2; x<<=2;}
    return 32-n-(x>>31);
}

void Updata(int x, int v)
{
    for (T[x+=M]+=v, x>>=1; x; x>>=1) //
        T[x]=T[x<<1]+T[(x<<1)+1]; /// updata father by their children
}

int request(int s, int t)
{
    int res=0;
    for (s+=M-1, t+=M+1; s^t^1; s>>=1, t>>=1)/// change [,] to (,); s^t==1 refer to the interval is empty
    {
        if(~s&1) res+=T[s^1];
        if( t&1) res+=T[t^1];
    }
    return res;
}

int main ()
{
    int cas;
    scanf("%d", &cas);
    for (int I=1; I<=cas; ++I)
    {
        printf("Case %d:\n", I);
        int n;
        ///initialization
        scanf("%d", &n);
        M=1<<(bit(n));
//        printf("---%d  %d\n", M, bit(n));
        memset (T, 0, sizeof(T));
        for (int i=0; i<n; ++i)
            scanf("%d",  &T[i+M]);
        for (int i=(n+M-1)/2; i>0; --i)/// (n+m-1)/2 is largest non-leaf node
            T[i]=T[2*i]+T[2*i+1];

        char op[20];
        int a, b;
        while (~scanf("%s", op))
        {
            if (op[0]=='E')
                break;
            scanf("%d %d", &a, &b);
            if (op[0]=='Q')
                printf("%d\n", request(a-1, b-1));
            if (op[0]=='A')
                Updata(a-1, b);
            if (op[0]=='S')
                Updata(a-1, -b);
        }
    }
    return 0;
}


hdu1754 I Hate It

水题。。。单点替换 区间最值

hdu1394 Minimum Inversion Number

最小逆序数 水题, 直接暴力。 

不过线段树确实优化不少,对求3元组 , 类似ai>aj>ak (i>j>k)这样的也可以用线段树, 下面有例子

单点增减 区间求和

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int maxn=5000+123;
int T[maxn*3];
int a[maxn];
int M;
int bit(int x)/// get highest 1 in bit-number
{
    if(x==0)return 0;
    int n=31;
    if((x>>16)==0){n-=16; x<<=16;}
    if((x>>24)==0){n-=8; x<<=8;}
    if((x>>28)==0){n-=4; x<<=4;}
    if((x>>30)==0){n-=2; x<<=2;}
    return n-(x>>31);
}

int Query(int s, int t)
{
    int res=0;
    for (s+=M-1, t+=M+1; s^t^1; s>>=1, t>>=1)
    {
        if(~s&1) res+=T[s^1];
        if( t&1) res+=T[t^1];
    }
    return res;
}

void Updata(int x)
{
    for (T[x+=M]=1, x>>=1; x; x>>=1)
        T[x]=T[x<<1]+T[(x<<1)+1];
}

void init(int x)
{
    memset (T, 0, sizeof(T));
    M=1<<bit(x);
}

int main ()
{
    int n;
    while (~scanf("%d", &n))
    {
        init(n);
        int inv=0;
        for (int i=0; i<n; ++i)
        {
            scanf("%d", a+i);
            inv+=Query(a[i]+1, n-1);
            Updata(a[i]);
        }
        int ans=inv;
        for (int i=0; i<n-1; ++i)
        {
            inv+=n-a[i]-a[i]-1;
            ans=min(inv, ans);
        }
        printf("%d\n", ans);
    }
    return 0;
}


hdu2795 Billboard

维护最大值 查询时自上向下, 改了N次, 终于过了, 线段树灵活运用才是王道!

单点增减, 区间查询满足给点值的最小下标位置

void Updata (int x, int v)
{
    for (T[x+=M]-=v, x>>=1; x; x>>=1)
        T[x]=max(T[x<<1], T[x<<1|1]);
}

int Query (int s, int t, int x)
{
    int res=-1, r;
    s+=M-1;t+=M+1;
    for (r=1; (r<<1)<t;)
    {
        T[r<<1]>=x?(r<<=1):(r=(r<<1|1));
    }
    if(r>s && r<t)res=r;
    else res=t;
    return res;
}


http://www.acdream.net/problem.php?id=1123

群赛的题, 求一个序列中满足aj>ai>ak 且满足j>i>k的3元组的个数, 和hdu1394 Minimum Inversion Number 类似, 2个线段树维护,

 第一次找aj>ai ,且j>i的对数, 然后再次维护一个新树, 找3元组的个数


类似题解:

dp[i][1] 表示 有多少对 aj > ai,j < i,dp[i][2]表示有多少对ak > aj > ai , k < j < i

dp[i][1] += dp[j][0] ( aj > ai 且 j < i)

dp[i][2] += dp[j][1] ( aj > ai 且 j < i)


long long Request(int s, int t)
{
    long long res=0;
    for (s+=M-1, t+=M+1; s^t^1; s>>=1, t>>=1)
    {
        if(~s&1) res+=T[s^1];
        if( t&1) res+=T[t^1];
    }
    return res;
}

void Updata(int x, int v)
{
    for (T[x+=M]+=v, x>>=1; x; x>>=1)
        T[x]=T[x<<1]+T[x<<1|1];
}

void init()
{
    M=1<<bit(n);
    memset (T, 0, sizeof(T));
}

int main ()
{
    while (~scanf("%d", &n))
    {
        init();
        memset (inv, 0, sizeof(inv));
        for (int i=0; i<n; ++i)/// 得到一次逆序,
        {
            scanf("%d", a+i);
            inv[i]=Request(a[i]+1, n)+inv[i];
            Updata(a[i], 1);
        }
        memset (T, 0, sizeof(T));
        long long ans=0;
        for (int i=0; i<n; ++i)
        {
            ans=Request(a[i]+1, n)+ans;
            Updata(a[i], inv[i]);
        }
        printf("%lld\n", ans);
    }
    return 0;
}



线段树详解(单点更新与成段更新\区间更新操作)

本文纯属原创,转载请注明出处,谢谢。 距离第一次接触线段树已经一年多了,再次参加ACM暑假集训,这一次轮到我们这些老家伙们给学弟学妹们讲解线段树了,所以就自己重新把自己做过的题目看了一遍,然后写篇博客...
  • u014705673
  • u014705673
  • 2015年07月06日 15:57
  • 6208

POJ - 2155 Matrix (二维树状数组 + 区间修改 + 单点求值 或者 二维线段树 + 区间更新 + 单点求值)

POJ - 2155 Matrix Time Limit: 3000MS   Memory Limit: 65536KB   64bit IO Format: %I64d & %I64u ...
  • qq_18661257
  • qq_18661257
  • 2015年08月07日 20:16
  • 1222

树状数组的区间修改,单点查询

树状数组的区间修改
  • u013514722
  • u013514722
  • 2014年10月17日 21:49
  • 2642

HDOJ 5316 Magician【线段树 单点更新 区间查询】

Magician Time Limit: 18000/9000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Tota...
  • wyjwyl
  • wyjwyl
  • 2016年07月26日 17:35
  • 222

Necklace (线段树单点更新+区间查询+离线操作)

Problem Description Mery has a beautiful necklace. The necklace is made up of N magic balls. Each...
  • qq_19327307
  • qq_19327307
  • 2014年08月13日 20:02
  • 202

【单点更新,区间查询,线段树】【HDU1166】【敌兵布阵】

线段树要捡回来学了 才知道以前抄的模板就是杭电传奇学长写的,写起来更有激情了; 一点注意: 单点更新完后记得pushup(),向上更新信息 以下是对线段树的理解 线段树的节点...
  • zy691357966
  • zy691357966
  • 2015年04月07日 21:14
  • 259

HDOJ 4325 Flowers 【线段树 离散化 区间更新 单点查询】

Flowers Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total ...
  • wyjwyl
  • wyjwyl
  • 2015年11月15日 17:23
  • 376

HDU 1166 敌兵布阵 (线段树单点更新+区间查询入门)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1166 题面: 敌兵布阵 Time Limit: 2000/1000 MS (Ja...
  • David_Jett
  • David_Jett
  • 2015年10月08日 09:23
  • 428

hdu 1754 I Hate It 线段树单点更新区间查询

题目: I Hate It Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Othe...
  • xiaoli_nu
  • xiaoli_nu
  • 2017年02月07日 16:36
  • 90

线段树基础:单点更新,区间最值(和)查询

线段树基础:单点更新,区间最值查询
  • ACGoxy
  • ACGoxy
  • 2017年07月31日 09:42
  • 211
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:线段树(堆式)[单点更新, 区间查询]
举报原因:
原因补充:

(最多只允许输入30个字)