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

原创 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;
}



版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

Color the ball - HDU 1556 - 线段树 区间更新单点查询

Color the ball - HDU 1556 - 线段树 区间更新单点查询  国际惯例中文题目不解释,思路直接裸线段树,Lazy思想入门题。  Lazy传送门:延迟更新详解AC代码:// // ...

ny 123 士兵杀敌(四)-- 线段树(区间更新,单点查询)

士兵杀敌(四) 时间限制:2000 ms  |  内存限制:65535 KB 难度:5 描述 南将军麾下有百万精兵,现已知共有M个士兵,编号为1~M,每次有任务的时候,...

HDU 1754 多个学生偷改成绩问最高分-线段树-(单点更新,区间查询)

题意:n个学生有初始成绩,现在有m个操作,(Q,a,b):询问区间学号为[a,b]的学生的最好成绩;(U,a,b):修改学号为a的学生的成绩为b,要你执行这m项操作。 分析: 单点更新,区间查询。确切...

zoj (单点更新区间查询:线段树)

题意:有n天,每天都可以买西瓜,每个西瓜的价格是ai,每个西瓜能吃bi天。问这n天每天都有西瓜吃的最小的代价是多少?如果你在第i天买了一个西瓜,那么之前买的西瓜就要全部扔掉,才能开始吃新的西瓜。 定...

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

Problem Description Mery has a beautiful necklace. The necklace is made up of N magic balls. Each b...

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

Magician Time Limit: 18000/9000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Tota...

UVALive 6838 Flipping Parentheses(线段树、单点更新、区间查询)

题目链接: UVALive 6838 Flipping Parentheses 题意: 给出一个长度为n个串,每个字符只能是’(‘或’)’,而且左括号和右括号个数相等,在操作的过程中,要保证这个...

HDU-1556-Color the ball-线段树+区间更新+单点查询

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1556 好吧,一道这么简单的题结果因为我的粗心卡了一下午。。。orz.... #include #inc...
  • wlxsq
  • wlxsq
  • 2015-08-03 16:57
  • 291

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

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

HDU 4819:单点更新,区间查询的二维线段树

我越来越觉得之前自己的代码写的就跟shi一样…… 题意很简单,矩阵中指定一个方形
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

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