【bzoj2223】[Coci 2009]PATULJCI 主席树

题目描述

样例输入

10 3
1 2 1 2 1 2 3 2 3 3
8
1 2
1 3
1 4
1 5
2 5
2 6
6 9
7 10

样例输出

no
yes 1
no
yes 1
no
yes 2
no
yes 3

样例描述

第一行输入n和lim,为序列数的个数和数的范围(1≤a[i]≤lim)
第二行输入n个数。
第三行输入m,为询问个数。
以下m行输入询问,如题。
对于每个询问,如果存在,输出yes和这个数,否则输出no。

题解:

主席树.
因为个数要大于((r - l + 1)/2)所以我们应该查询左子树相减的个数是否大于这个数,右子树相减是否大于这个数.(这个是利用左右子树的个数和主席树的性质来解)
ps:貌似我没有好好利用lim,还是离散化了,_huaji_

#include <iostream>
#include <cstdio>
#include <algorithm>

using namespace std;
const int maxN = 3e5 + 7;

int root[maxN],a[maxN],s[maxN],cnt;
struct Node {
	int lc,rc;
	int ans;
} tree[maxN * 20];

inline int read() {
	int x = 0,f = 1;
	char c = getchar();
	while(c < '0' || c > '9') {if(c == '-')f = -1;c = getchar();}
	while(c >= '0' && c <= '9') {x = x * 10 + c - '0';c = getchar();}
	return x * f;
}

void add(int &now,int last,int l,int r,int p) {
	now = ++ cnt;
	tree[now].ans = tree[last].ans + 1;
	tree[now].lc = tree[last].lc;
	tree[now].rc = tree[last].rc;
	if(l == r)return;
	int mid = (l + r) >> 1;
	if(mid >= p) add(tree[now].lc,tree[last].lc,l,mid,p);
	else add(tree[now].rc,tree[last].rc,mid + 1,r,p);
}

int query(int L,int R,int l,int r,int p) {
	if(l == r) return l;
	int mid = (l + r) >> 1;
	if(tree[tree[R].lc].ans - tree[tree[L].lc].ans > p) return query(tree[L].lc,tree[R].lc,l,mid,p);
	if(tree[tree[R].rc].ans - tree[tree[L].rc].ans > p) return query(tree[L].rc,tree[R].rc,mid + 1,r,p);
	return 0;
}

int main() {
	freopen("bzoj2223.in","r",stdin);
	freopen("bzoj2223.out","w",stdout);
	int n,m,lim;
	n = read();lim = read();
	for(int i = 1; i <= n; ++ i)
		s[i] = a[i] = read();
	sort(s + 1,s + n + 1);
	for(int i = 1; i <= n; ++ i) {
		int p = lower_bound(s + 1,s + n + 1,a[i]) - s;
		add(root[i],root[i - 1],1,n,p);
	}
	int l,r;
	m = read();
	while(m --) {
		l = read();
		r = read();
		int p = query(root[l - 1],root[r],1,n,(r - l + 1) >> 1);
		p != 0 ? printf("yes %d
" ,s[p]) : printf("no
") ; 
	}
	return 0;
}
原文地址:https://www.cnblogs.com/tpgzy/p/9325810.html