线段树的运用 以及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。
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。
- 线段树的运用 以及poj上的经典题目
- poj上的经典线段树
- 线段树的经典题目及题解
- poj2828-Buy Tickets(线段树的经典运用)
- Buy Tickets+POJ+线段树单点更新的灵活运用
- ACM知识点以及在POJ上对应的题目
- POJ 2638 筛选法的经典运用
- 线段树的题目
- 线段树的题目
- POJ 3667 线段树 区间合并经典题目
- POJ 2482——Stars in Your Window(线段树+扫描线,二维区域最值转化为线段树-经典)最浪漫的题目
- 几个线段树经典运用
- poj上搜索经典题目
- 线段树的特殊运用
- 线段树更进一步的运用
- POJ上的题目分类
- poj 3468 A Simple Problem with Integers(线段树成段更新,懒惰标记的使用)经典题目
- 一些线段树的题目
- JSTL fmt 标签导致中文乱码的问题
- gdb list 不能显示代码的原因
- C#操作XML小结
- OCX控件相关
- 上传资料被锁定帐户
- 线段树的运用 以及poj上的经典题目
- HTTP协议状态码的含义
- uva 11151
- QT 创建主窗口 MainWindow 实例
- arraylist用法
- 【 DLL 破解】 .NET DLL 一次破解说明
- 常用的正则表达式
- 指针 与 引用
- linux进程调度浅析