又是一年一度的暑假集训 然而前几天刚做完搜索 还木有做明白 现在就跑过来做线段树 唉 不知道我这个弱弱什么时候才能变得不那么弱~
HDU 4006 与 POJ 2828 两题相类似
HDU 4006 是找第K大的数 POJ 2828是把数字插入到指定位置然后输出arry 两题都属于线段树单点更新的问题
HDU 4006
tree[root].sum 记录该节点一共有多少个数字 若目前出现的数字为cnt 在Query时查询第 cnt-k+1 就好了
需要注意的问题是 n 表示操作数目 所以建树的时候要注意 在此处本弱弱WA了好几次- -||
下面是ac代码
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn = 1001000;
int n,k;
struct tree
{
int l,r,sum;
}tree[maxn*4];
void PushUp(int root)
{
tree[root].sum = tree[root<<1].sum + tree[root<<1|1].sum;
}
void Build(int root,int l,int r)
{
tree[root].l = l;
tree[root].r = r;
if(tree[root].l == tree[root].r)
{
tree[root].sum = 0;
return ;
}
int mid = (tree[root].l + tree[root].r)/2;
Build(root<<1,l,mid);
Build(root<<1|1,mid+1,r);
PushUp(root);
}
void Update(int root,int num)
{
if(tree[root].l == tree[root].r)
{
tree[root].sum ++;
return ;
}
int mid = (tree[root].l + tree[root].r)/2;
if(num <= mid)
Update(root<<1,num);
if(num > mid)
Update(root<<1|1,num);
PushUp(root);
}
int Query(int root,int pos)
{
if(tree[root].l == tree[root].r)
{
return tree[root].l;
}
int ret;
if(pos <= tree[root<<1].sum) //tree[root<<1].sum 表示lson所含数的个数 若查询pos大的数 是否在lson内 若不在则查询rson的pos-tree[root<<1].sum大的数 这好好理解一下就行了 POJ 2828 也主要运用这个
ret = Query(root<<1,pos);
else //(pos > tree[root<<1].sum)
ret = Query(root<<1|1,pos-tree[root<<1].sum);
return ret;
}
int main()
{
while(~scanf("%d%d",&n,&k))
{
Build(1,1,maxn);
char str[2];
int cnt = 0,num;
while(n--)
{
scanf("%s",str);
if(str[0] == 'I')
{
scanf("%d",&num);
Update(1,num);
cnt ++;
}
if(str[0] == 'Q')
{
int ans = Query(1,cnt-k+1);
cout<<ans<<endl;
}
}
}
return 0;
}
POJ 2828
题意 给出 posi vali 顺序插入数字 再输出结果 大家看hint就应该能明白
思路和上题差不多
不同的是逆序进行插入 因为正序进行的话 前面的会影响后面的位置 所以逆序进行就可以解决这个问题
每个节点存的是还有多少空位置 1 为有数字 0 为空
pos位在lson内找不到 则在rson找(pos-lson.sum)位
赘述一下 插入相同位置的问题 假如说
2 3
2 5
0 1
1 2
output 1 2 5 3
这组数据 两个数 3和5都插在2位置上面,我们逆序进行插入 先插入的是5 后插的是3 当插入3的时候 询问(0,1,2)作为lson的父节点时候 lson.sum = 0已经没有位置可插入了所以 3 自然就插入到 rson的第一个位置(pos-lson.sum)这样就解决插入同一个位置的问题了哈~
#include <iostream>
#include <cstdio>
#include <cmath>
#define maxn 200005
using namespace std;
int seq[maxn];
struct tree
{
int l,r,sp;
}tree[maxn*4];
int n,p[maxn],v[maxn];
void BuildTree(int root,int l,int r)
{
tree[root].l = l;
tree[root].r = r;
if(tree[root].l == tree[root].r)
{
tree[root].sp = 1;
return ;
}
int mid = (tree[root].l+tree[root].r)/2;
BuildTree(root<<1,l,mid);
BuildTree(root<<1|1,mid+1,r);
tree[root].sp = tree[root<<1].sp+tree[root<<1|1].sp;
}
void update(int root,int l,int r,int pos,int val)
{
if(tree[root].l == tree[root].r)
{
seq[tree[root].l] = val;
tree[root].sp = 0;
return;
}
int mid = (tree[root].l + tree[root].r)/2;
if(tree[root<<1].sp >= pos)
update(root<<1,l,mid,pos,val);
else
update(root<<1|1,mid+1,r,pos-tree[root<<1].sp,val);
tree[root].sp = tree[root<<1].sp+tree[root<<1|1].sp;
}
int main()
{
while(~scanf("%d",&n))
{
BuildTree(1,1,n);
for(int i = 1;i <= n;i ++)
scanf("%d%d",&p[i],&v[i]);
//nixu
for(int i = n;i >= 1;i --)
update(1,1,n,p[i]+1,v[i]);
for(int i = 1;i <= n;i ++)
printf("%d ",seq[i]);
printf("\n");
}
return 0;
}
如有疏漏 还请各位指出啊~