tozangezan's diary

勝手にソースコードをコピペして利用しないでください。

AOJ 2563: The J-th Number

相当いろんな解法があるらしい。

考えられる一番直感的な方法で解いた。動的確保の二種の和のsegtreeにpairをぶちこんでソートして後半のクエリで二分探索。動的確保で何個ノードが必要になるのかがよくわからない。計算量(特にソート部分)もよくわからない。

#include<stdio.h>
#include<algorithm>
#include<vector>
using namespace std;
struct wolf{
	vector<pair<int,int> >A;
	vector<pair<int,long long> >B;
	int left;
	int right;
	wolf(){
		left=right=-1;
	}
};
wolf pool[3500000];
int sz=0;
void add(int a,int b,int c,int d,int e,int f){
	if(d<a||b<c)return ;
	if(c<=a&&b<=d){
		pool[e].A.push_back(make_pair(f,1));
		return;
	}
	//printf("%d: %d %d\n",e,a,b);
	int num=min(b,d)-max(a,c)+1;
	pool[e].B.push_back(make_pair(f,num));
	int to;
	if(min((a+b)/2,d)>=max(a,c)){
		to=pool[e].left;
		if(!~to){
			to=pool[e].left=sz++;
		}
		add(a,(a+b)/2,c,d,to,f);
	}
	if(min(b,d)>=max((a+b)/2+1,c)){
		to=pool[e].right;
		if(!~to){
			to=pool[e].right=sz++;
		}
		add((a+b)/2+1,b,c,d,to,f);
	}
}
long long cnt(int a,int b,int c,int d,int e,int f){
//	printf("%d %d %d %d %d %d\n",a,b,c,d,e,f);
	if(d<a||b<c)return 0LL;
	if(c<=a&&b<=d){
		long long ret=(*(lower_bound(pool[e].B.begin(),pool[e].B.end(),make_pair(f+1,0LL))-1)).second;
		int num=b-a+1;
		ret+=(long long)((*(lower_bound(pool[e].A.begin(),pool[e].A.end(),make_pair(f+1,0))-1)).second)*num;
		return ret;
	}
	int num=min(b,d)-max(a,c)+1;
	long long ret=(long long)((*(lower_bound(pool[e].A.begin(),pool[e].A.end(),make_pair(f+1,0))-1)).second)*num;
	int to=pool[e].left;
	if(~to){
		ret+=cnt(a,(a+b)/2,c,d,to,f);
	}
	to=pool[e].right;
	if(~to){
		ret+=cnt((a+b)/2+1,b,c,d,to,f);
	}
	return ret;
}
int main(){
	int a,b,c;
	scanf("%d%d%d",&a,&b,&c);
	sz++;
	for(int i=0;i<b;i++){
		int p,q,r;
		scanf("%d%d%d",&p,&q,&r);
		p--;q--;
		add(0,(1<<30)-1,p,q,0,r);
	}
	for(int i=0;i<sz;i++){
	//	printf("%d: %d %d\n",i,pool[i].A.size(),pool[i].B.size());
		pool[i].A.push_back(make_pair(0,0));
		pool[i].B.push_back(make_pair(0,0));
		
		std::sort(pool[i].A.begin(),pool[i].A.end());
		long long now=0;
		for(int j=0;j<pool[i].A.size();j++){
		//	if(j)printf("%d: %d %d\n",i,pool[i].A[j].first,pool[i].A[j].second);
			now+=pool[i].A[j].second;
			pool[i].A[j].second=now;
		}
		std::sort(pool[i].B.begin(),pool[i].B.end());
		now=0;
		for(int j=0;j<pool[i].B.size();j++){
	//		if(j)printf("%d: %d %d\n",i,pool[i].B[j].first,pool[i].B[j].second);
			now+=pool[i].B[j].second;
			pool[i].B[j].second=now;
		}
	}
	for(int i=0;i<c;i++){
		int p,q;
		long long r;
		scanf("%d%d%lld",&p,&q,&r);
		p--;q--;
		int left=0;
		int right=1000000007;
		while(left+1<right){
			int M=(left+right)/2;
			long long val=cnt(0,(1<<30)-1,p,q,0,M);
		//	printf("%lld\n",val);
			if(val>=r)right=M;
			else left=M;
		}
		printf("%d\n",right);
	}
}