POJ2761--Feed the dogs

Description

Wind loves pretty dogs very much, and she has n pet dogs. So Jiajia has to feed the dogs every day for Wind. Jiajia loves Wind, but not the dogs, so Jiajia use a special way to feed the dogs. At lunchtime, the dogs will stand on one line, numbered from 1 to n, the leftmost one is 1, the second one is 2, and so on. In each feeding, Jiajia choose an inteval[i,j], select the k-th pretty dog to feed. Of course Jiajia has his own way of deciding the pretty value of each dog. It should be noted that Jiajia do not want to feed any position too much, because it may cause some death of dogs. If so, Wind will be angry and the aftereffect will be serious. Hence any feeding inteval will not contain another completely, though the intervals may intersect with each other.

Your task is to help Jiajia calculate which dog ate the food after each feeding.

Input

The first line contains n and m, indicates the number of dogs and the number of feedings.

The second line contains n integers, describe the pretty value of each dog from left to right. You should notice that the dog with lower pretty value is prettier.

Each of following m lines contain three integer i,j,k, it means that Jiajia feed the k-th pretty dog in this feeding.

You can assume that n<100001 and m<50001.

Output

Output file has m lines. The i-th line should contain the pretty value of the dog who got the food in the i-th feeding.

Sample Input

7 2
1 5 2 6 3 7 4
1 5 3
2 7 1

Sample Output

32

神题啊,线段树,树状数组,Treap,SBT,Splay都可以做。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
using namespace std;
#define maxn 200080
int A[maxn],Ans[maxn];
struct Que
{
	int from,to,k,id;
}que[maxn>>1];

bool cmp(Que a,Que b)
{
	if(a.from < b.from)	return 1;
	else if(a.from > b.from)	return 0;
	else return a.to < b.to;
}

struct Node
{
	Node * ch[2];
	int r,v,s;
	/*
	bool operator < (const Node & a) const
	{
		return r < a.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;
	}
}*root;

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();
		o -> ch[0] = o -> ch[1] = NULL;
		o -> v = x;
		o -> r = rand();
		o -> s = 1;
	}
	else 
	{
		int d = o -> cmp(x);
		if(d == -1)	d = 0;
		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 * tmp = o;
		if(o -> ch[0] == NULL)
		{
			o = o -> ch[1];
			delete tmp;
			tmp = NULL;
		}
		else if(o -> ch[1] == NULL)
		{
			o = o -> ch[0];
			delete tmp;
			tmp = NULL;
		}
		else
		{
			int d2 = (o -> ch[0] -> r > o -> ch[1] -> r?1:0);
			rotate(o,d2);
			remove(o -> ch[d2],x);
		}
	}
	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 Rank(Node * o,int x)
{
	int ans = 0;
	while(o)
	{
		if(o -> v == x)
		{
			if(o -> ch[0])	ans += o -> ch[0] -> s;
			return ans;
		}
		else if(o -> v > x)
		{
			o = o -> ch[0];
		}
		else 
		{
			if(o -> ch[0])	ans += o -> ch[0] -> s;
			ans++;
			o = o -> ch[1];
		}
	}
	return ans;
}

int Kth(Node * o,int k)
{
	while(k)
	{
		if(o -> ch[0])
		{
			if(o -> ch[0] ->s  >= k) o = o -> ch[0];
			else if(o -> ch[0] -> s == k-1)	return o -> v;
			else k -= o -> ch[0] -> s + 1,o = o -> ch[1];
		}
		else if( k == 1 )	return o -> v;
		else k--,o = o -> ch[1];
	}
}

void DeleteTreap(Node *& o)
{
	if(o == NULL)	return;
	if(o -> ch[0])	DeleteTreap(o -> ch[0]);
	if(o -> ch[1])	DeleteTreap(o -> ch[1]);
	delete o;
	o = NULL;
}

int main()
{
	//freopen("in.txt","r",stdin);
	int n,m;
	while(scanf("%d%d",&n,&m)==2)
	{
		root = NULL;
		for(int i = 0;i < n;i++)	
		{
			scanf("%d",&A[i]);
			///insert(root,A[i]);
		}
		for(int i = 0;i < m;i++)	
		{
			scanf("%d%d%d",&que[i].from,&que[i].to,&que[i].k);
			que[i].from--;que[i].to--;
			que[i].id = i+1;
		}
		sort(que,que+m,cmp);
		for(int i = que[0].from;i <= que[0].to;i++)
		{
			insert(root,A[i]);
		}
		Ans[que[0].id] = Kth(root,que[0].k);
		int l = que[0].from,r = que[0].to;
		for(int i = 1;i < m;i++)
		{
			if(r >= que[i].from)
			{
				if(l < que[i].from)
					for(int j = l;j < que[i].from;j++)	remove(root,A[j]);
				else if(l > que[i].from)
					for(int j = que[i].from;j < l;j++)	insert(root,A[j]);
				if(r < que[i].to)
					for(int j = r+1;j <= que[i].to;j++)	insert(root,A[j]);
				else if(r > que[i].to)
					for(int j = que[i].to+1;j <= r;j++)	remove(root,A[j]);
			}
			else 
			{
				for(int j = l;j <= r;j++)	remove(root,A[j]);
				for(int j = que[i].from;j <= que[i].to;j++)	insert(root,A[j]);
			}
			Ans[que[i].id] = Kth(root,que[i].k);
			l = que[i].from,r = que[i].to;
		}
		for(int i = 1;i <= m;i++)	printf("%d\n",Ans[i]);
		DeleteTreap(root);
	}
	return 0;
}

接下来是线段树做法:

/*
首先将数据离散化。
然后节点表示这段区间的数有多少个。
update函数用来添点删点。
二分查找就行。

*/
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
#define maxn 100080
#define lson id<<1,l,mid
#define rson id<<1|1,mid+1,r
int X[maxn],XX[maxn],Ans[maxn];

struct Que
{
	int from,to,k,id;
}que[maxn];

bool cmp(Que a,Que b)
{
	if(a.from < b.from)	return 1;
	else if(a.from > b.from)	return 0;
	else return a.to < b.to;
}

struct ST
{
	int l,r,num;
}st[maxn<<2];

void PushUp(int id)
{
	st[id].num = st[id<<1].num + st[id<<1|1].num;
}

void buildtree(int id,int l,int r)
{
	st[id].l = l,st[id].r = r;
	if(l == r)
	{
		st[id].num = 0;
		return;
	}
	int mid = (l+r) >> 1;
	buildtree(lson);
	buildtree(rson);
	PushUp(id);
}

void Update(int id,int pos,int ope)
{
	if(st[id].l == st[id].r)
	{
		st[id].num += ope;
		return;
	}
	if(st[id<<1].r >= pos)	Update(id<<1,pos,ope);
	else Update(id<<1|1,pos,ope);
	PushUp(id);
}

int query(int id,int l,int r)
{
	if(st[id].l == l && st[id].r == r)
	{
		return st[id].num;
	}
	if(st[id<<1].r >= r)
	{
		return query(id<<1,l,r);
	}
	if(st[id<<1|1].l <= l)
	{
		return query(id<<1|1,l,r);
	}
	return query(id<<1,l,st[id<<1].r) + query(id<<1|1,st[id<<1|1].l,r);
}

int main()
{
	//freopen("in.txt","r",stdin);
	int n,m;
	while(scanf("%d%d",&n,&m)==2)
	{
		for(int i = 1;i <= n;i++)
		{
			scanf("%d",&X[i]);
		}
		memcpy(XX,X,sizeof(X));
		sort(X+1,X+n+1);
		buildtree(1,1,n);
		for(int i = 0;i < m;i++)
		{
			scanf("%d%d%d",&que[i].from,&que[i].to,&que[i].k);
			que[i].id = i+1;
		}
		sort(que,que+m,cmp);
		int l = 1,r = n;
		for(int i = 1;i <= n;i++)
		{
			int pos = lower_bound(X+1,X+n+1,XX[i]) - X;
			Update(1,pos,1);
		}
		for(int i = 0;i < m;i++)
		{
			int u = que[i].from,v = que[i].to;
			if(r >= u)
			{
				if(l < que[i].from)
				{
					for(int j = l;j < que[i].from;j++)
					{
						int pos = lower_bound(X+1,X+n+1,XX[j]) - X;
						Update(1,pos,-1);
					}
				}
				if(r > que[i].to)
				{
					for(int j = que[i].to + 1;j <= r;j++)
					{
						int pos = lower_bound(X+1,X+n+1,XX[j]) - X;
						Update(1,pos,-1);
					}
				}
				else if(r < que[i].to)
				{
					for(int j = r+1;j <= que[i].to;j++)
					{
						int pos = lower_bound(X+1,X+n+1,XX[j]) - X;
						Update(1,pos,1);
					}
				}
			}
			else 
			{
				for(int j = l;j <= r;j++)	
				{
					int pos = lower_bound(X+1,X+n+1,XX[j])-X;
					Update(1,pos,-1);
				}
				for(int j = que[i].from;j <= que[i].to;j++)
				{
					int pos = lower_bound(X+1,X+n+1,XX[j])-X;
					Update(1,pos,1);
				}		
			}
			//树已经维护好了,接下来就是二分查找的过程。
			int ll = 1,rr = n;
			int k = que[i].k;
			while(ll < rr)
			{
				int mid = (ll + rr) >> 1;
				if(query(1,1,mid) >= k)	rr = mid;
				else ll = mid + 1;
			}
			Ans[que[i].id] = X[ll];
			l = que[i].from,r = que[i].to;
		}
		for(int i = 1;i <= m;i++)
		{
			printf("%d\n",Ans[i]);
		}
	}
	return 0;
}


 接下来是树状数组。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define maxn 100080
int c[maxn];
int X[maxn],XX[maxn],Ans[maxn];
int lowbit(int x)
{
	return x&(-x);
}

struct Que
{
	int from,to,k,id;
}que[maxn];

bool cmp(Que a,Que b)
{
	if(a.from < b.from)	return 1;
	else if(a.from > b.from)	return 0;
	else return a.to < b.to;
}

void update(int x,int add)
{
	while(x < maxn)
	{
		c[x]+=add;
		x+=lowbit(x);
	}
}

int getsum(int x)
{
	int sum = 0;
	while(x > 0)
	{
		sum += c[x];
		x -= lowbit(x);
	}
	return sum;
}

int main()
{
	//freopen("in.txt","r",stdin);
	int n,m;
	while(scanf("%d%d",&n,&m)==2)
	{
		for(int i = 1;i <= n;i++)	scanf("%d",&X[i]);
		for(int i = 0;i < m;i++)
		{
			scanf("%d%d%d",&que[i].from,&que[i].to,&que[i].k);
			que[i].id = i + 1;
		}
		sort(que,que+m,cmp);
		memset(c,0,sizeof(c));
		memcpy(XX,X,sizeof(X));
		sort(X+1,X+n+1);
		for(int i = 1;i <= n;i++)	
		{
			int pos = lower_bound(X+1,X+n+1,XX[i]) - X;
			update(pos,1);
		}
		int l = 1,r = n;
		for(int i = 0;i < m;i++)
		{
			int u = que[i].from,v = que[i].to;
			if(r >= u)
			{
				if(l < que[i].from)
				{
					for(int j = l;j < que[i].from;j++)
					{
						int pos = lower_bound(X+1,X+n+1,XX[j]) - X;
						update(pos,-1);
					}
				}
				if(r > que[i].to)
				{
					for(int j = que[i].to + 1;j <= r;j++)
					{
						int pos = lower_bound(X+1,X+n+1,XX[j]) - X;
						update(pos,-1);
					}
				}
				else if(r < que[i].to)
				{
					for(int j = r+1;j <= que[i].to;j++)
					{
						int pos = lower_bound(X+1,X+n+1,XX[j]) - X;
						update(pos,1);
					}
				}
			}
			else 
			{
				for(int j = l;j <= r;j++)
				{
					int pos = lower_bound(X+1,X+n+1,XX[j]) - X;
					update(pos,-1);
				}
				for(int j = que[i].from;j <= que[i].to;j++)
				{
					int pos = lower_bound(X+1,X+n+1,XX[j]) - X;
					update(pos,1);
				}
			}
			int ll = 1,rr = n;
			int k = que[i].k;
			while(ll < rr)
			{
				int mid = (ll + rr) >> 1;
				if(getsum(mid) >= k)	rr = mid;
				else ll = mid + 1;
			}
			Ans[que[i].id] = X[ll];
			l = que[i].from,r = que[i].to;
		}
		for(int i = 1;i <= m;i++)	printf("%d\n",Ans[i]);
	}
	return 0;
}


接下来是一点都不SB的SB树:


 

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define nil 0
#define maxn 200080
int key[maxn],Left[maxn],Right[maxn],Size[maxn];
int A[maxn],Ans[maxn];
int root,node;
int record;//This is used for the commented Delete
struct Que
{
	int from,to,k,id;
}que[maxn];

bool cmp(Que a,Que b)
{
	if(a.from < b.from)	return 1;
	else if(a.from > b.from)	return 0;
	else return a.to < b.to;
}

inline void Left_Rotate(int & x)
{
	int k = Right[x];
	Right[x] = Left[k];
	Left[k] = x;
	Size[k] = Size[x];
	Size[x] = Size[Left[x]] + Size[Right[x]] + 1;
	x = k;
}

inline void Right_Rotate(int & y)
{
	int k = Left[y];
	Left[y] = Right[k];
	Right[k] = y;
	Size[k] = Size[y];
	Size[y] = Size[Left[y]] + Size[Right[y]] + 1;
	y = k;
}

void Maintain(int & T,bool flag);

void Insert(int & T,int v)
{
	if(T == nil)
	{
		key[T = ++node] = v;
		Size[T] = 1;
		Left[T] = Right[T] = nil;
	}
	else 
	{
		Size[T]++;
		if(v < key[T])	Insert(Left[T],v);
		else
			Insert(Right[T],v);大于等于就在右边添加。
		Maintain(T,v >= key[T]);
	}
}

int Delete(int & T,int v)///Delete函数我不是很清楚。
{
	if(!T)	return 0;
	Size[T]--;
	if( (v == key[T]) || (v < key[T] && Left[T] == nil) || 
		(v > key[T] && Right[T] == nil) )
	{
		if(Left[T] == nil || Right[T] == nil)如果只有单支子系,直接用儿子代替他就行了。
		{
			int p = T;
			T = Left[T] + Right[T];
			return p;
		}
		else
		{
				//int p = Delete(Left[T],key[T] + 1);
				int p = Delete(Left[T],v+1);
				key[T] = key[p];///否则的话,用左支的最大值来替代这个删除点。
				return p;
		}
	}
	else
	{
		if(v < key[T])
			return Delete(Left[T],v);
		else return Delete(Right[T],v);
	}
}

void Maintain(int & T,bool flag)
{
	if(flag == false)
	{
		if(Size[Left[Left[T]]] > Size[Right[T]])
			Right_Rotate(T);
		else if(Size[Right[Left[T]]] > Size[Right[T]])
		{
			Left_Rotate(Left[T]);
			Right_Rotate(T);
		}
		else return;
	}
	else
	{
		if(Size[Right[Right[T]]] > Size[Left[T]])
			Left_Rotate(T);
		else if(Size[Left[Right[T]]] > Size[Left[T]])
		{
			Right_Rotate(Right[T]);
			Left_Rotate(T);
		}
		else return;
	}
	Maintain(Left[T],false);
	Maintain(Right[T],true);
	Maintain(T,false);
	Maintain(T,true);
}

int Search(int x,int k)///寻找=k的那个数
{
	if(x == nil || k == key[x])
		return x;
	if(k < key[x])
		return Search(Left[x],k);
	else return Search(Right[x],k);
}

int Select(int T,int k)///选择第k小的数
{
	int r = 1 + Size[Left[T]];
	if(k == r)
		return key[T];
	else if(k < r)
		return Select(Left[T],k);
	else return Select(Right[T],k - r);
}

int Succ(int T,int k)///找后继
{
	if(T == nil)
		return k;
	if(key[T] <= k)
		return Succ(Right[T],k);
	else 
	{
		int r = Succ(Left[T],k);
		if(r == k)	return key[T];
		else return r;
	}
}

int Pred(int T,int k)///找前驱
{
	if(T == nil)
		return k;
	if(key[T] >= k)
		return Pred(Left[T],k);
	else
	{
		int r = Pred(Right[T],k);
		if(r == k)
			return key[T];
		else return r;
	}
}

int Rank(int T,int k)///k在这颗树中排第几大
{
	if(T == nil)	return 1;
	if(key[T] >= k)	return Rank(Left[T],k);
	else return Size[Left[T]] + Rank(Right[T],k) + 1;
}

int main()
{
	//freopen("in.txt","r",stdin);
	int n,m;
	while(scanf("%d%d",&n,&m)==2)
	{
		for(int i = 1;i <= n;i++)	scanf("%d",&A[i]);
		for(int i = 0;i < m;i++)
		{
			int u,v,k;	scanf("%d%d%d",&u,&v,&k);
			que[i].from = u,que[i].to = v,que[i].k = k,que[i].id = i+1;
		}
		memset(Size,0,sizeof(Size));
		sort(que,que+m,cmp);
		root = node = 0;
		for(int i = 1;i <= n;i++)	Insert(root,A[i]);
		int l = 1,r = n;
		for(int i = 0;i < m;i++)
		{
			int u = que[i].from,v = que[i].to,k = que[i].k;
			if(r >= u)
			{
				if(l < u)
				{
					for(int j = l;j < u;j++)	Delete(root,A[j]);
				}
				if(r < v)
				{
					for(int j = r+1;j <= v;j++)	Insert(root,A[j]);
				}
				else if(r > v)
				{
					for(int j = v+1;j <= r;j++)	Delete(root,A[j]);
				}
			}
			else 
			{
				for(int j = l;j <= r;j++)	Delete(root,A[j]);
				for(int j = u;j <= v;j++)	Insert(root,A[j]);
			}
			Ans[que[i].id] = Select(root,k);
			l = u,r = v;
		}

		for(int i = 1;i <= m;i++)	printf("%d\n",Ans[i]);
	}
	return 0;
}


 接下来是专门解决区间第K小的主席树:

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <queue>
#include <string>
#include <string>
using namespace std;
#define maxn 100080
#define maxm 5600800
int T[maxn],key[maxn],a[maxn];
int c[maxm],lson[maxm],rson[maxm];
int n,m,tot;
void Hash_init()
{
	tot = 0;
	for(int i = 1;i <= n;i++)	a[i] = key[i];
	sort(key+1,key+n+1);
}

int Hash(int k)
{
	return lower_bound(key+1,key+n+1,k) - key;
}

int build(int l,int r)
{
	int root = tot++;
	c[root] = 0;
	if(l != r)
	{
		int mid = (l+r) >> 1;
		lson[root] = build(l,mid);
		rson[root] = build(mid+1,r);
	}
	return root;
}

int Update(int root,int pos,int val)
{
	int newnode = tot++,tmp = newnode;
	c[newnode] = c[root] + val;
	int l = 1,r = n;
	while(l < r)
	{
		int mid = (l+r) >> 1;
		if(pos <= mid)
		{
			lson[newnode] = tot++;	rson[newnode] = rson[root];
			newnode = lson[newnode];	root = lson[root];
			r = mid;
		}
		else
		{
			rson[newnode] = tot++;
			lson[newnode] = lson[root];
			newnode = rson[newnode];
			root = rson[root];
			l = mid + 1;
		}
		c[newnode] = c[root] + val;
	}
	return tmp;
}

int query(int left_root,int right_root,int k)
{
	int l = 1,r = n;
	while(l < r)
	{
		int mid = (l+r) >> 1;
		if(c[lson[left_root]] - c[lson[right_root]] >= k)
		{
			r = mid;
			left_root = lson[left_root];
			right_root = lson[right_root];
		}
		else 
		{
			l = mid + 1;
			k -= c[lson[left_root]] - c[lson[right_root]];
			left_root = rson[left_root];
			right_root = rson[right_root];
		}
	}
	return l;
}

int main()
{
	while(scanf("%d%d",&n,&m)==2)
	{
		for(int i = 1;i <= n;i++)	scanf("%d",&key[i]);
		Hash_init();
		T[n+1] = build(1,n);
		for(int i = n;i >= 1;i--)	
		{
			int pos = Hash(a[i]);
			T[i] = Update(T[i+1],pos,1);
		}
		while(m--)
		{
			int u,v,k;	scanf("%d%d%d",&u,&v,&k);
			printf("%d\n",key[query(T[u],T[v+1],k)]);
		}
	}
	return 0;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值