HDU 4006 POJ 2828 线段树(排列/找有序位置)

4 篇文章 0 订阅
1 篇文章 0 订阅

又是一年一度的暑假集训 然而前几天刚做完搜索 还木有做明白 现在就跑过来做线段树 唉 不知道我这个弱弱什么时候才能变得不那么弱~

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


如有疏漏 还请各位指出啊~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值