POJ2828 Buy Tickets

首先让我们感谢昨天BestCoder的出题人Claris,以及各位Hacker,让我这个帮老妈刷票刷了半个小时结果,19:40多才开始打得水笔A了3道题,本来只有rank30左右的,结果硬生生地被hack到了rank10,结果rating还是只涨了100多(话说我某次rank30多也是涨100多啊),下一场还是不能打DIV1,不过没关系,反正DIV2都AK不了还做毛DIV1啊。

然后呢,继续填坑。

今天突然发现了一个黑科技。

没错就是这道题。

题意的话很简单啊,序列插入操作。

来来来Splay走起来~~~~~~~~~~~~~~~~~~~~~~~~~~~

????????????

TLE!!!!

出题人你几个意思啊,Splay你都卡。

然后发现线段树好像可做。

从后往前插入,每次找到第pos+1个空位,然后在这里插,把这个空位删掉。

嗯就这么结束了。

当然不!

众所周知某一部分线段树能完成的操作树状数组也可以完成。

只要满足区间减法就行了(Jxr:树状数组这么短,就像我一样(嘿嘿嘿))

于是我们可以二分+BIT,两个log。

但是这不合理啊,树状数组这么短的东西怎么可以这么慢呢。

于是我闲得无聊逛评论区,结果发现了黑科技。

BIT的sumseek(k)操作。

找到前缀和>=k的第一个位置。

具体见代码。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=200000+5;
int d[N],v[N],n;
int lowbit(int x){
	return x&-x;
}
int sumseek(int k){
	int ans=0,sum=0;
	for(int i=18;i>=0;i--){
		ans+=(1<<i);
		if(ans>=n||sum+d[ans]>=k)ans-=(1<<i);
		else sum+=d[ans];
	}
	return ans+1;
}
void add(int x,int v){
	for(;x<=n;x+=lowbit(x))d[x]+=v;
}
int pos[N],val[N];
int main(){
	//freopen("a.in","r",stdin);
	while(scanf("%d",&n)==1){
		for(int i=1;i<=n;i++)add(i,1);
		for(int i=1;i<=n;i++)scanf("%d%d",&pos[i],&val[i]);
		for(int i=n;i>=1;i--){
			int k=sumseek(pos[i]+1);
			v[k]=val[i];
			add(k,-1);
		}
		for(int i=1;i<=n;i++)
		printf("%d ",v[i]);
		putchar('\n');
	}
	return 0;
}


你可能感兴趣的:(POJ2828 Buy Tickets)