1. 程式人生 > >Luogu P1533 可憐的狗狗

Luogu P1533 可憐的狗狗

題目背景

小卡由於公務需要出差,將新家中的狗狗們託付給朋友嘉嘉,但是嘉嘉是一個很懶的人,他才沒那麼多時間幫小卡喂狗狗。

題目描述

小卡家有N只狗,由於品種、年齡不同,每一隻狗都有一個不同的漂亮值。漂亮值與漂亮的程度成反比(漂亮值越低越漂亮),吃飯時,狗狗們會按順序站成一排等著主人給食物。

可是嘉嘉真的很懶,他才不肯喂這麼多狗呢,這多浪費時間啊,於是他每次就只給第i只到第j只狗中第k漂亮的狗狗餵食(好狠心的人啊)。而且為了保證某一隻狗狗不會被喂太多次,他喂的每個區間(i,j)不互相包含。

輸入輸出格式

輸入格式:

第一行輸入兩個數n,m,你可以假設n<300001 並且 m<50001;m表示他餵了m次。

第二行n個整數,表示第i只狗的漂亮值為ai。

接下來m行,每行3個整數i,j,k表示這次餵食喂第i到第j只狗中第k漂亮的狗的漂亮值。

輸出格式:

M行,每行一個整數,表示每一次喂的那隻狗漂亮值為多少。

輸入輸出樣例

輸入樣例#1: 複製

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

輸出樣例#1: 複製

3
2

裸的平衡樹(可惜菜雞不會)

先要離散化

因為區間互不包含,所以若l是單調遞增,r也一定單調遞增,所以果斷排序

排序後用佇列維護選的數,要從中選取第K大的,權值樹狀陣列上二分,好寫有跑的快

nlg n lg n

菜雞之前因為沒有記q陣列的id,並且忘了離散化後答案要是原來的答案不能是離散化後的答案,樣例也忒水了

而WA了一次,

#include<cstdio>
#include<algorithm>
using namespace std;

int read()
{
	int ret=0; char ch=getchar();
	while(ch<'0'||ch>'9') ch=getchar();
	while(ch>='0'&&ch<='9')
		ret=(ret<<1)+(ret<<3)+ch-'0',ch=getchar();
	return ret;
}

const int N=1e6+4;
int n,m,b[N],l,r,mid,ans[N],s,ll,rr,bb[N];
struct A{
	int id,x;
}a[N];
struct B{
	int id,l,r,k;
}q[N];

bool cmp(A i,A j)
{
	return i.x<j.x;
}

bool cmp1(B i,B j)
{
	return i.l<j.l;
}

struct C
{
	int c[N];
	inline void add(int x,int k)
	{
		for(int i=x;i<=n;i+=i&-i) c[i]+=k;
	}
	
	inline int sum(int x)
	{
		int ret=0;
		for(int i=x;i;i-=i&-i) ret+=c[i];
		return ret;
	}
}tree;

int main()
{
	n=read(),m=read();
	for(int i=1;i<=n;i++) a[i]=(A){i,read()};
	sort(a+1,a+n+1,cmp);
	for(int i=1;i<=n;i++) b[a[i].id]=i,bb[i]=a[i].x;
	for(int i=1;i<=m;i++) q[i]=(B){i,read(),read(),read()};
	sort(q+1,q+m+1,cmp1);
	ll=1,rr=0;
	for(int i=1;i<=m;i++)
	{
		while(rr<q[i].r) 
			rr++,tree.add(b[rr],1);	
		while(ll<q[i].l)
			tree.add(b[ll],-1),ll++;
		l=1,r=n; 
		while(l<=r)
		{
			mid=l+r>>1;
			if(tree.sum(mid)>q[i].k)  r=mid-1;
				else if(tree.sum(mid)<q[i].k) l=mid+1;
					else s=mid,r=mid-1;
		}
		ans[q[i].id]=bb[s];
	}
	for(int i=1;i<=m;i++) printf("%d\n",ans[i]);
	return 0;
}