POJ_2828解题报告

题目不再重述。

我也是看了解题报告的...之前怎么都想不到,如果正常模拟的话,每一次插入元素都必须准确的知道位置在pos的元素究竟是哪一个,知道连在那一个元素后面,才能正确的串成一个队嘛。。

如果用数组-- 向中间加元素要一个一个的挪

用链表--n^2   超时了。。

其他的数据结构?怎么都想不到一种可以动态维护记录每个元素(相对整个队列)绝对位置的 可insert 结构...


这时候就需要找规律了:加入0 1,0  2

后面来的2会把1挤掉,这是不是说后面的元素“更优先”一些呢?继续想下去,发现:最后一个元素插入的位置总是它最终的绝对位置!!

然后?--那倒数第二呢?它插入的位置似乎没啥规律,可是去掉已经固定位置的元素在看呢?

这时需要一个可以动态数出前面有几个空位的东西了--我用的是树状数组。

#include"stdio.h"
#include"stdlib.h"
#include"time.h"
#include"math.h"
#include"iostream"
#include"string.h"
#include"algorithm"
#include"vector"
#include"string"
#include"queue"
#include"map"

#define nmax 2001000
#define inf 0x7ffffff
#define eps 1e-8
#define PI 3.1415926535
#define PRIME 9999991
using namespace std;
int n;
int ans[nmax];
struct People{
    int pi,vi;
    int ti;
}peo[nmax];
//int pi[nmax],vi[nmax];
#define  lowbit(x)  (x)&(x^(x-1))
//int a[21];
int c[nmax];

void change(int k,int del)
{
	while ( k<=n ) {
		c[k]+=del;
		k+=lowbit(k);
	}
	return ;
}

int get_num(int k)
{
	int z=0;
	while ( k>0 ) {
		z+=c[k];
		k-=lowbit(k);
	}
	return z;
}

int get_ans(int x,int y)
{
	return get_num(y)-get_num(x-1);
}


int get_pos(int v){
    ///二分找到插入位置:
    int mid,x=1,y=n+1;
    while(x<y){
        mid=x+(y-x)/2;
        int front_num=mid-get_num(mid);
        ///how many 0 is in the front of mid;
        if(front_num<=v){x=mid+1;}
        //else if(front_num==v){break;}
        else {y=mid;}
    }
    while(ans[x]!=-1)x++;
    return x;
}
bool cmp(People a,People b){
    if(a.pi==b.pi)return a.ti>b.ti;
    return a.pi<b.pi;
}
int main(){

    while(scanf("%d",&n)==1){
        int i;
        for(i=1;i<=n;i++){
            //scanf("%d%d",&pi[i],&vi[i]);
            //pi[i]++;
            scanf("%d%d",&peo[i].pi,&peo[i].vi);
            peo[i].pi++;
        }
        //io
        //sort(peo,peo+n,cmp);
        memset(ans,-1,sizeof(ans));
        memset(c,0,sizeof(c));

        for(i=n;i>0;i--){
            int ipos=get_pos(peo[i].pi);

            change(ipos,1);

            ans[ipos]=peo[i].vi;
        }

        for(i=2;i<=n+1;i++){
            printf("%d",ans[i]);
            if(i!=n+1)putchar(' ');
        }
        puts("");
    }


return 0;}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值