第一道:
HDU 1754 单点更新,区间查询最大值,水题……
#include
#include
#include
#include
#include
第二道:
HDU 1698 区间更新,区间查询,lazy标记种类,水……
#include
#include
#include
#include
#include
第三道:
HDU 1394 单点更新,区间查询,线段树、树状数组、归并排序求逆序数。
解法一:线段树
#include
#include
#include
#include
#include
解法二:树状数组:
#include
#include
#include
#include
#include
第四道:
POJ 2528 线段树+离散化
这题T了几个小时了,晕死了……原来是在离散化的时候多了点时间,尼玛,让我debug了两个小时!!!!
其实我这样离散化还有个bug,因为单点离散化和区间离散化是不一样的。
比如这个例子:
3
1 10
1 3
6 10
我这个代码就输出2,本来是3的,POJ 的数据弱了。
不过改一点就可以过了,离散化的时候可以离散成:Map[c[i]]=(i+1)*2,然后查询的时候,总区间也*2就行了,这样在区间与区间之间就可以查询得到了。懒得改了,想做好的就按这样做吧。
#include
#include
#include
#include
#include
第五道:
HDU 2795 几何中的单点更新
思路:刚开始看这题的时候也不知道该怎么用线段树做,想了好久也不知道,然后看了下别人的解题报告才知道这么容易,只是想不到啊!用叶结点表示长方形的行,然后叶结点的域表示的是当前行的宽(或者还剩多少可以容纳的宽度),这样就可以轻松解决了。线段树不建太长,有多少行就建多少,如果n大的话,就建n的长度就行了,这点看刚才看题的时候10^9就怕了,所以就没想到这么机智的做法。
#include
#include
#include
#include
#include
第六道:
POJ 3667 区间合并,设置左右中区间,然后更新的时候合并。刚开始想的时候确实没想到这么机智的做法,我想的做法是加个lazy标记,然后查询的时候再加个flag标记,初始flag=0,如果找到flag=1,然后如果=1的话,递归就不进行下去了, 这样应该也可以做这道题,不过可能代码比较长忽悠一点吧……
#include
#include
#include
#include
#include
第七道:
POJ 2892 & HDU 1540
解法一:树状数组查找第k小的数的下标。
树状数组查找第k小的数做的,挺机智的。
查找第k小的数,这个知识学习了一下午才知道什么意思,尼玛……其实意思就是查找值为k的数在树状数组中其和从1开始到哪个下标其和等于k。比如树状数组中的:c[1]=1,c[2]=1,c[3]=0,c[4]=1,c[5]=0,c[6]=0,c[7]=1,c[8]=2,c[9]=1.
则sum[5]=1,现在查找k=1的下标,那就是4;再比如sum[8]=2,查找k=2的下标就是8,这个求法可以用下面代码的find_kth函数二分逼近法求出。
但是在HDU 1540上过不了,所说是数据水了。改了一上午还是过不了,还以为是数据有错了,然后拿别人代码交了一发线段树就过了,难道这题限制用树状数组?算了,还是用线段树写发区间合并吧!
#include
#include
#include
#include
#include
解法二:线段树区间合并
这个和hotel那题差不多,都是区间合并,代码差不多。
#include
#include
#include
#include
#include
第八道:
HDU 2871 区间合并
这题比较晕……靠……刚开始直接输入scanf("%s%d",s,%l);然后一直T,检查了好久都没发现哪里有超时的可能。然后不用文件输入,手动输入的时候才发现Reset后面不用输数字了,尼玛……晕……
与hotel那题的函数是一样的,只不过处理不一样。
不过这里因为是一堆一堆处理的,所以比较麻烦,但是线段树的函数还是不变的。
因为要处理询问一段一段,所以可以把其放进向量vector里记录,加入和删除比较方便。
#include
#include
#include
#include
#include
#define lson i<<1,l,mid
#define rson i<<1|1,mid+1,r
#define maxn 200010
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
int sum[maxn],lsum[maxn],rsum[maxn],lazy[maxn];
void pushdown(int i,int v)
{
if(lazy[i]!=-1)
{
int l=i<<1,r=i<<1|1;
lazy[l]=lazy[r]=lazy[i];
sum[l]=lsum[l]=rsum[l]=(lazy[i]?0:(v-(v>>1)));//lazy为1表清空房间
sum[r]=lsum[r]=rsum[r]=(lazy[i]?0:(v>>1));//右孩子值
lazy[i]=-1;
}
}
void pushup(int i,int v)
{
int l=i<<1,r=i<<1|1;
lsum[i]=lsum[l];
if(lsum[l]==v-(v>>1))//若左子树全空
lsum[i]+=lsum[r];//则加上右子树的左区间
rsum[i]=rsum[r];
if(rsum[r]==v>>1)
rsum[i]+=rsum[l];
sum[i]=max(max(sum[l],sum[r]),rsum[l]+lsum[r]);
}
void update(int i,int l,int r,int L,int R,int v)
{
if(L<=l&&r<=R)
{
sum[i]=lsum[i]=rsum[i]=(v?0:r-l+1);
lazy[i]=v;
return ;
}
pushdown(i,r-l+1);
int mid=(l+r)>>1;
if(L<=mid) update(lson,L,R,v);
if(mid>1;
if(sum[i<<1]>=v) return query(lson,v);
else if(rsum[i<<1]+lsum[i<<1|1]>=v)
return mid-rsum[i<<1]+1;
return query(rson,v);
}
void build(int i,int l,int r)
{
sum[i]=lsum[i]=rsum[i]=r-l+1;
lazy[i]=-1;
if(l==r) return ;
int mid=(l+r)>>1;
build(lson);
build(rson);
}
struct block
{
int Begin,End;
}y;
bool cmp(const block &a,const block &b)
{
return a.Beginv;
vector::iterator it;
int main()
{
//freopen("test.txt","r",stdin);
int n,m;
while(~scanf("%d%d",&n,&m))
{
build(1,1,n);
v.clear();
while(m--)
{
int l;
char s[7];
scanf("%s",&s);
if(s[0]=='N')
{
scanf("%d",&l);
if(sum[1]v.size()) puts("Reject Get");
else printf("Get at %d\n",v[l-1].Begin);
}
}
puts("");
}
return 0;
}
第九道:
HDU 1542 开始利用线段树求解矩形面积的并、交、以及周长.
刚开始接触这类型的时候,真的不知道该如何下手。没想到线段树还能拿来求解矩形面积的并、交和周长,感觉挺神的,后面就看了这方面的博客,看到一个挺好的解释和代码,研究了一天半才全部搞明白……
先看这个博客前面线段树中结点域的解释,然后边看图边看代码就理解了。
昨天看明白之后,还以为全部理解了,然后今天敲的时候,没得答案,然后把过程都输出了,一个一个对比,然后才发现建树的时候错了。我们一般建树都是build(i<<1,l,mid);build(1<<1|1,mid+1,r);而这个线段树求解矩形的并不这样建的,有点区别。因为这样建树的话,叶子结点l和r相同,就是一个点,而不是线段了,所以要让叶子结点是线段,然后又不能在更新线段的时候变成更新一个点,所以得这样建树:build(1<<1,l,mid);build(1<<1|1,mid,r);建的这个右子树不一样。
学习参考博客:http://www.cnblogs.com/ka200812/archive/2011/11/13/2247064.html
#include
#include
#include
#include
#include
第十道:
HDU 1255 求解矩形并的面积
这题和上一题处理的代码都一样,我还没变呢就过了……算的时候当然是用覆盖两次以上的算啦!在上一题中把线段树节点里面的len域改成覆盖一次和覆盖两次的就行了,覆盖两次以上的肯定有并的了。比较难的处理在pushUp那个函数,只要理解了上一题,这一题应该没有那么难理解了。
#include
#include
#include
#include
#include
第十一道:
HDU 1828 线段树求矩形并的周长
其实就是用了上面第九道题的模板就A了,哈哈,太爽了。
#include
#include
#include
#include
#include
第十二道:
POJ 2828 逆序查找空位插入法
思路:线段树单点更新查找空位插入。
不理解的可以看这个网址的解释:http://www.cnblogs.com/CheeseZH/archive/2012/04/29/2476134.html
#include
#include
#include
#include
#include
第十三道:
POJ 2155 二维线段树
思路:二维线段树就是每个节点套一棵线段树的树。
刚开始因为题目是求A[I,J],然后在y查询那直接ans^=Map[i][j]的时候没看懂,后面自己把图画出来了才理解。
因为只有0和1,所以可以用异或来搞,而不需要每次都需要修改。
#include
#include
#include
#include
#include
第十四道:
ZOJ 2859 二维线段树
思路:自己写的第二发二维线段树1A,哈哈,看来对二维的push操作比较了解了;但是还没遇到在两个线段树中同时进行push操作的,其实这题我是想在x维和y维同时进行push操作的,但是想了好久不会,然后看到这题又给出10秒,然后想想在x维线段直接单点查询肯定也过了,然后就只有pushup操作,没有lazy延时pushdown操作。不过也A了,想找题即在二维同时进行pushup和pushdown操作的。
#include
#include
#include
#include
#include
HDU 4614
思路:把区间空的地方记录下来求和,然后1的时候求1到a-1的0个数为cnt,查询cnt+1的位置就是第一个位置,查询cnt+b的位置就是最后一个位置;2的时候直接查询,然后再更新。
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include
#include
#include
#include
#include