线段树的运用 以及poj上的经典题目

来源:互联网 发布:dnf时装搭配软件 编辑:程序博客网 时间:2024/05/21 09:18
看了一下线段树,作了几个相关题目:
1 poj3468 A Simple Problem with Integers
线段树的简单应用,给出Q个问题,当为C 2 3 3表示在区间[2,3]上的每个数都增加3,当为Q 2 3 时表示求区间[2,3]上的和
我的方法是:
首先定义一个结构体:
struct Node{
    int left,right;
    __int64 sum;表示区间的基本值
    __int64 add;表示区间的增量
};
1首先输入的是N个数,每个位上的值,使用insert(i,1)将这个数插入,我们需要进行到区间长度为1时终止,在这个过程中所有经过的区间都必须进行sum+=i操作。
2进行操作C l r c时,找到对应的区间的话,其add+=c,在这个查找过程中所经过的区间都必须进行sum+=(l-r+1)*c
3进行操作Q l r 时,我们找到对应的区间[l,r],对其sum+add*(l-r+1),需要注意的是我们从父区间往下找的时候需要把父节点的add计算在内,因此需要进行s[fu].add*(l-r+1)+...
关键代码如下:
插入每个位上的数时:
void insert(int l,int d,int idx)
{
    s[idx].sum+=d;
    if(s[idx].left==s[idx].right)
        return;
    int mid=(s[idx].left+s[idx].right)>>1;
    if(l<=mid)
        insert(l,d,2*idx);
    else
        insert(l,d,2*idx+1);

}
进行操作C:
void operatorC(int l,int r,int c,int idx)
{
    if((s[idx].left==l) && (s[idx].right==r))
    {
        s[idx].add+=c;
        return;
    }
    s[idx].sum+=(r-l+1)*c;
    int mid=(s[idx].left+s[idx].right)>>1;
    if(r<=mid)
        operatorC(l,r,c,2*idx);
    else if(l>mid)
        operatorC(l,r,c,2*idx+1);
    else
    {
        operatorC(l,mid,c,2*idx);
        operatorC(mid+1,r,c,2*idx+1);
    }
}
进行操作Q:
__int64 operatorQ(int l,int r,int idx)
{
    if((s[idx].left==l) && (s[idx].right==r))
    {
        return s[idx].sum+s[idx].add*(r-l+1);
    }
    int mid=(s[idx].left+s[idx].right)>>1;
    if(r<=mid)
        return s[idx].add*(r-l+1)+operatorQ(l,r,2*idx);
    else if(l>mid)
        return s[idx].add*(r-l+1)+operatorQ(l,r,2*idx+1);
    else
        return s[idx].add*(r-l+1)+operatorQ(l,mid,2*idx)+operatorQ(mid+1,r,2*idx+1);
}
我刚开始想的是对每个区间都进行计算它所得到的增量,这样每次C一次的话,程序都要递归到最后的叶节点,超时,然后修改了下,增加一个add变量,这样算区间和时将父区间的增量加进来就行了。
程序跑了2829MS 勉强A了。。。
2 poj3246 Balanced Lineup
题目比较简单,任给一区间,求其最大最小值差,主要是在节点增加两个变量,指示该区间的最小和最大值,刚开始的时候超时,改成scanf后A了。
3 POJ 2894Ancient Keyboard
典型的线段树,区间统计个数问题,刚开始时提交了两次都是RE,仔细检查原来是建立树的时候a可以为0,我建立的是[1,1000],改成
[0,1000]就ok了,水过。。。
4 poj2182 Lost Cows
之前好像遇到过这类题目,说一排牛,每个牛都有唯一的一个brand,但是现在牛不是按照brand升序的顺序排列的。现在已知每个牛前面的所有比它的brand小的个数,求现在的这排牛的brand。我之前好像又是用到快排又是逆序的,超时,现在仔细考虑了一下,其实挺简单的。我们首先将这列数的brand赋值为1...N,即假设已经按照升序排列了,然后对照small数组,进行修改它们的brand。例如s[3],如果前面比它的brand小的牛个数小于它前面的总的牛个数,则它的brand相应的减去两者差ch,前面比它的brand大的牛为ch个,然后从前面的牛中与当前牛的brand比较,大于=当前brand的牛的brand进行+1,这样修改后的brand数组即为最后要求的结果。
5 POJ 2777 Count Color
区间段颜色数,典型的线段树题,这道题和poj2528Mayor's posters差不多,只不过这个是任给一个区间段求其颜色数,而后面的是求总的区间的海报数,我在这个题目的基础上改了下,即使查询的时候改动了下,其余不变,基本思想是一样的,都用到了延迟方法,即当给区间[a,b]涂色时,如果已经涂色,且涂的不是同一个颜色,则将它的颜色传递给儿子节点,并将它的颜色置0。
原创粉丝点击