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

来源:互联网 发布:金山软件 港股 编辑:程序博客网 时间:2024/05/16 01:16

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

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

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

0 0
原创粉丝点击