P3567 [POI2014]KUR-Couriers

LuoguP3567 [POI2014]KUR-Couriers

菜死了,竟然没看出来这是一道主席树的模板题.还自己瞎YY了写奇技淫巧。
首先([l,r])这个区间的主席树我们是很好求的。
如果一个数出现的次数严格大于((r - l + 1) / 2)
那么,第((r - l + 1) /2)大的数肯定是他,
但是,怎么判断第((r - l + 1)/2)大的数到底出现没出现更多次,好像没有思路。
但是,在递归查询第(k)大的时候,查询的排名不随区间改变而改变就好了
煮个栗子
普通的主席树如果左儿子(默认使用当前区间的主席树)有(k - 1)个数
我们将问题转化为查询右儿子第一大
但是这道题去查询右儿子第(k)大,如果右儿子也不足(k),说明没有数出现了((r - l + 1) /2)

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cctype>
using namespace std;
const int N = 5e5 + 3;
struct node{
	int sum;
	int lc,rc;	
}a[N * 30];
int v[N],b[N],rt[N];
int n,m,t;
inline int read(){
	int v = 0,c = 1;char ch = getchar();
	while(!isdigit(ch)){
		if(ch == '-') c = -1;
		ch = getchar();	
	}
	while(isdigit(ch)){
		v = v * 10 + ch - 48;
		ch = getchar();	
	}
	return v * c;	
}
inline void ins(int &u,int l,int r,int x){
	a[++t] = a[u];
	u = t;
	if(l == r){
		a[u].sum ++;
		return ;
	}
	int mid = (l + r) >> 1;
	if(x <= mid) ins(a[u].lc,l,mid,x);
	else ins(a[u].rc,mid + 1,r,x);
	a[u].sum = a[a[u].lc].sum + a[a[u].rc].sum;
}
inline int query(int u1,int u2,int l,int r,int x){
	if(l == r) return l;
	int s1 = a[a[u2].lc].sum - a[a[u1].lc].sum,s2 = a[a[u2].rc].sum - a[a[u1].rc].sum;
//	printf("%d %d
",s1,s2);
	int mid = (l + r) >> 1;
	if(s1 > x) return query(a[u1].lc,a[u2].lc,l,mid,x);
	else if(s2 > x) return query(a[u1].rc,a[u2].rc,mid + 1,r,x);
	else return 0;	
}
int main(){
	n = read(),m = read();
	for(int i = 1;i <= n;++i) v[i] = b[i] = read();
	sort(b + 1,b + n + 1);
	b[0] = unique(b + 1,b + n + 1) - b - 1;
	for(int i = 1;i <= n;++i){
		rt[i] = rt[i - 1];
		v[i] = lower_bound(b + 1,b + b[0] + 1,v[i]) - b;
		ins(rt[i],1,b[0],v[i]);
	}
	while(m--){
		int l = read(),r = read();
		int k = (r - l + 1) / 2;
		int ans = query(rt[l - 1],rt[r],1,b[0],k);
		printf("%d
",ans == 0 ? ans : b[ans]);	
	}
	return 0;	
}
原文地址:https://www.cnblogs.com/wyxdrqc/p/10641271.html