hdu 2711 Lost Cows(单点更新)

来源:互联网 发布:mac不能玩qq游戏 编辑:程序博客网 时间:2024/05/29 11:12

题目链接  : hdu 2711 Lost Cows

题目大意:有n头牛,编号从1到n,排成n行,现在它们的顺序打乱了,每一头牛站一行,现在只知道在它前面几行中比它编号小的头数,站在第一行的牛前面没有东西,所以输入数据从第二行开始,让你求牛此时的序列;

解析:比如 输入序列为 1 2 1 0 ,从左往右分别表示比第二行编号小的牛有1头,比第三行小的有2头....比最后一行小的有0头,我们可以从后往前看,比最后一行小的牛有0头,说明最后一行牛的标号为1,因为1是最小的,假设我们有5头牛,比最后一头小的为2,则编号为3,由此可见,若比最后一头小的数有m,则最后一头的编号始终为m+1,然后再看倒数第二行,都是一样的道理。

这题用线段数维护区间内数的个数,开始与区间长度相同,后来每次从最后往前更新,对应叶子节点的区间值变为0,可以说是查询区间第k大;


#include<iostream>#include<cstdio>#define maxn 11111#define lson l,m,rt<<1#define rson m+1,r,rt<<1|1using namespace std;int sum[maxn<<2];int L[maxn],x[maxn];int cnt;void pushup(int rt){    sum[rt]=sum[rt<<1]+sum[rt<<1|1];  //线段树维护的是区间的和,区间的和代表有几个数,更新查询时可以判断第几大}void build(int l,int r,int rt){    if(l==r)    {        sum[rt]=(r-l+1); //区间初始化为区间的长度        return;    }    int m=(l+r)>>1;    build(lson);    build(rson);    pushup(rt);    //向上更新}void update(int p,int l,int r,int rt){    if(l==r)    {        sum[rt]=0; //每次更新,这个数就被用过了,下次不再用,所以这个叶子节点赋值为一        L[cnt++]=l;  //记录当前第p大的数为l        return ;    }    int m=(l+r)>>1;    if(p<=sum[rt<<1])    update(p,lson);  //区间记录的是区间内数字的个数,p表示第p大的数,也就是p个数,若p比左儿子区间的个数少,说明这个数在做儿子里    else update(p-sum[rt<<1],rson);  //否则要减去左儿子的个数,在右儿子里找p-sum[rt<<1]大的数    pushup(rt);  //向上更新}int query(int l,int r,int rt){    if(l==r)  return l;  //这次询问的目的在于找到排在第一行的数,因为他前面不存在数,也就没有比它小的的数,所以该叶子节点始终没有被更新,值始终为1,只要找到这个一就行    int m=(l+r)>>1;    int ret=0;    if(sum[rt<<1]==1)  ret=query(lson);  //左儿子区间等于1,往左儿子里查找    else ret=query(rson);  //否则往右儿子里查找    return ret;}int main(){    int n;    while(~scanf("%d",&n))    {            cnt=0;            fill(L,L+maxn,0);            build(1,n,1);           for(int i=0;i<n-1;i++)  scanf("%d",&x[i]);           for(int i=n-2;i>=0;i--)  update(x[i]+1,1,n,1);  //从最后一行的开始更新           printf("%d\n",query(1,n,1)); //询问第一行的标号           for(int i=cnt-1;i>=0;i--)  printf("%d\n",L[i]);    }    return 0;}


0 0
原创粉丝点击