Poj 2182-Lost Cows(Treap||树状数组+二分答案)

题目链接:点击打开链接

题意:n个牛编号为1-n 现在编号顺序已经打乱,给出a[i] ,a[i] 代表i位置前面有几个小于它的编号,求编号顺序。

倒着推,对于最后一个a[i] , 最后位置编号肯定是 a[i]+1,然后在1-n个编号中删掉当前编号,继续往前推。。即求第 a[i]+1小数,初始容器中有n个数(1-n) ,每求出来一个就删掉。先用平衡树水了一发。。明天写树状数组解法。

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <string>
#include <cctype>
#include <vector>
#include <cstdio>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#define maxn 8005
#define _ll __int64
#define ll long long
#define INF 0x3f3f3f3f
#define Mod 1<<40+10
#define pp pair<int,int>
#define ull unsigned long long
using namespace std;
int n,ans[maxn];
struct node{
	node *ch[2];
	int r,v,s;
	node (){}
	node (int v){ch[0]=NULL;ch[1]=NULL;r=rand();this->v=v;s=1;}
	bool operator <(const node& c)const{
		return r<c.r;
	}
	int cmp(int x)const {
		if(x==v)return -1;
		return x<v?0:1;
	}
	void maintain(){
		s=1;
		if(ch[0]!=NULL)s+=ch[0]->s;
		if(ch[1]!=NULL)s+=ch[1]->s;
	}
};
void rotate(node* &o,int d){
	node *k=o->ch[d^1];o->ch[d^1]=k->ch[d];k->ch[d]=o;
	o->maintain();k->maintain();o=k;
}
void insert(node* &o,int x)
{
	if(o==NULL) o=new node(x);
	else{
		int d=o->cmp(x);
		insert(o->ch[d],x);
		if(o->ch[d]->r>o->r)rotate(o,d^1);
	}
	o->maintain();
}
void remove(node* &o,int x)
{
	int d=o->cmp(x);
	if(d==-1){
		node* u=o;
		if(o->ch[0]!=NULL&&o->ch[1]!=NULL){
			int d2=(o->ch[0]->r>o->ch[1]->r?1:0);
			rotate(o,d2);remove(o->ch[d2],x);
		}
		else{
			if(o->ch[0]==NULL)o=o->ch[1];
			else o=o->ch[0];
			delete u;
		}
	}
	else
	remove(o->ch[d],x);
	if(o!=NULL) o->maintain();
}
bool find(node* o,int x)
{
	while(o!=NULL)
	{
		int d=o->cmp(x);
		if(d==-1)return 1;
		else o=o->ch[d];
	}
	return 0;
}
int find_kth(node* o,int k)
{
	if(o==NULL||k>o->s)return -1;
	int s=(o->ch[0]==NULL?0:o->ch[0]->s);
	if(k==s+1)return o->v;
	else if(k<=s) return find_kth(o->ch[0],k);
	else return find_kth(o->ch[1],k-s-1);
}

void solve()
{
	node *root=NULL;
	for(int i=1;i<=n;i++)
		insert(root,i);
	for(int i=0;i<n-1;i++)
		scanf("%d",&ans[i]);
	for(int i=n-2;i>=0;i--){
		//cout<<"ans["<<i<<"]=="<<ans[i]<<endl;
		ans[i]=find_kth(root,ans[i]+1);
		//cout<<"ans["<<i<<"]=="<<ans[i]<<endl;
		remove(root,ans[i]);
	}
	printf("%d\n",root->v);
	for(int i=0;i<=n-2;i++)
		printf("%d\n",ans[i]);
}
int main()
{
	while(~scanf("%d",&n))
		solve();
	return 0;
}

树状数组+二分逼近。。Log(n)^2 还有一种Log(n)的写法至今还没会。。

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <string>
#include <cctype>
#include <vector>
#include <cstdio>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#define maxn 8003
#define _ll __int64
#define ll long long
#define INF 0x3f3f3f3f
#define Mod 10000007
#define pp pair<int,int>
#define ull unsigned long long
using namespace std;
int s[maxn],a[maxn],n;
int lowbit(int x){
	return x&(-x);
}
void update(int x,int num)
{
	while(x<=maxn){
		s[x]+=num;
		x+=lowbit(x);
	}
}
int getsum(int x){
	int ans=0;
	while(x>=1){
		ans+=s[x];
		x-=lowbit(x);
	}
	return ans;
}
int find_kth(int k)
{
	int l=1,r=maxn,mid;
	while(l<=r){
		mid=(l+r)/2;
		if(getsum(mid)>=k)
			r=mid-1;
		else
			l=mid+1;
	}
	if(l>maxn)return -1;
	return l;
}
void solve()
{
	for(int i=1;i<=n;i++)update(i,1);
	//for(int i=1;i<=n;i++)cout<<s[i]<<endl;
	for(int i=0;i<n-1;i++)
		scanf("%d",a+i);
	for(int i=n-2;i>=0;i--){
		a[i]=find_kth(a[i]+1);
		update(a[i],-1);
	}
	printf("%d\n",find_kth(1));
	for(int i=0;i<n-1;i++)
		printf("%d\n",a[i]);
}
int main()
{
	while (~scanf("%d", &n)) {
		solve();
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值