[bzoj3524][Poi2014]Couriers_主席树

Couriers bzoj-3524 Poi-2014

题目大意:给定n个数的序列,询问区间内是否存在一个在区间内至少出现了(区间长度>>1)次的数。如果有,输出该数,反之输出0。

注释:$1\le n,m\le 5\cdot 10^5$。



想法:主席树裸题。

主流做法就是弄一个Existence数组询问有没有这样的数,然后查询区间中位数即可。

但是可以在query的时候强行查询,因为没有输出0,直接输出即可。

最后,附上丑陋的代码... ...

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#define N 500010
using namespace std;
int cnt[N<<5],ls[N<<5],rs[N<<5],tot;
int a[N],b[N],root[N];
int build(int l,int r)
{
	int pos=++tot,mid=(l+r)>>1;
	if(l==r) return pos;
	ls[pos]=build(l,mid); rs[pos]=build(mid+1,r);
	return pos;
}
int update(int pre,int l,int r,int k)
{
	int pos=++tot,mid=(l+r)>>1;
	cnt[pos]=cnt[pre]+1;
	ls[pos]=ls[pre]; rs[pos]=rs[pre];
	if(l==r) return pos;
	if(k<=mid) ls[pos]=update(ls[pre],l,mid,k);
	else rs[pos]=update(rs[pre],mid+1,r,k);
	return pos;
}
// bool Existence(int x,int y,int l,int r,int Want)
// {
// 	if(l==r) return (cnt[y]-cnt[x])>=Want;
// 	int mid=(l+r)>>1;
// 	int LR=1;
// 	if(cnt[ls[y]]-cnt[ls[x]]>cnt[rs[y]]-cnt[rs[x]]) LR=0;
// 	else if(cnt[ls[y]]-cnt[ls[x]]<cnt[rs[y]]-cnt[rs[x]]) LR=2;
// 	if(LR==0) return Existence(ls[x],ls[y],l,mid,Want);
// 	if(LR==2) return Existence(rs[x],rs[y],mid+1,r,Want);
// 	return Existence(ls[x],ls[y],l,mid,Want)|Existence(rs[x],rs[y],mid+1,r,Want);
// }
// int query(int x,int y,int l,int r,int k)
// {
// 	int mid=(l+r)>>1;
// 	if(l==r) return b[l];
// 	int dlt=cnt[ls[y]]-cnt[ls[x]];
// 	if(dlt>=k) return query(ls[x],ls[y],l,mid,k);
// 	else return query(rs[x],rs[y],mid+1,r,k-dlt);
// }
int query(int x,int y,int l,int r,int k)
{
	int mid=(l+r)>>1;
	if(l==r) return l;
	int L=cnt[ls[y]]-cnt[ls[x]],R=cnt[rs[y]]-cnt[rs[x]];
	if(L>k) return query(ls[x],ls[y],l,mid,k);
	if(R>k) return query(rs[x],rs[y],mid+1,r,k);
	else return 0;
}
int main()
{
	int n,m; cin >> n >> m ;
	for(int i=1;i<=n;i++) scanf("%d",&a[i])/* ,b[i]=a[i] */;
	sort(b+1,b+n+1); /* int len=unique(b+1,b+n+1)-b-1; */
	root[0]=build(1,n);
	for(int i=1;i<=n;i++)
	{
		// int t=lower_bound(b+1,b+n+1,a[i])-b;
		root[i]=update(root[i-1],1,n,a[i]);
	}
	for(int x,y,i=1;i<=m;i++)
	{
		scanf("%d%d",&x,&y);
		// if(Existence(root[x-1],root[y],1,n,(y-x+1)/2+1)) printf("%d\n",query(root[x-1],root[y],1,n,(y-x+1)/2+1));
		// else printf("0\n");
		printf("%d\n",query(root[x-1],root[y],1,n,(y-x+1)>>1));
	}
	return 0;
}

小结:主席树真强... ...

原文地址:https://www.cnblogs.com/ShuraK/p/9383690.html

时间: 2024-10-24 16:29:03

[bzoj3524][Poi2014]Couriers_主席树的相关文章

[BZOJ2223][BZOJ3524][Poi2014]Couriers 主席树

3524: [Poi2014]Couriers Time Limit: 20 Sec  Memory Limit: 256 MBSubmit: 2436  Solved: 960[Submit][Status][Discuss] Description 给一个长度为n的序列a.1≤a[i]≤n.m组询问,每次询问一个区间[l,r],是否存在一个数在[l,r]中出现的次数大于(r-l+1)/2.如果存在,输出这个数,否则输出0. Input 第一行两个数n,m.第二行n个数,a[i].接下来m行,

BZOJ_3524_[Poi2014]Couriers_主席树

题意:给一个长度为n的序列a.1≤a[i]≤n. m组询问,每次询问一个区间[l,r],是否存在一个数在[l,r]中出现的次数大于(r-l+1)/2.如果存在,输出这个数,否则输出0. 分析: 区间众数我们可以用主席树搞定 具体地,比较左右子树siz大小即可 代码: #include <stdio.h> #include <string.h> #include <algorithm> using namespace std; #define N 500050 int t

BZOJ 3524: [Poi2014]Couriers( 主席树 )

卡我空间.... 这道题应该是主席树入门题...无修改 , 离散化都不用...出题人业界良心啊 一开始的空白树我 build 出来结果就多了整整 2n 个 Node , 然后就 MLE 了... ( 双倍经验 , 另一道见上图 ) ---------------------------------------------------------------------------------------------- #include<cstdio> #include<cstring&g

bzoj 3524 [POI2014]KUR-Couriers (主席树)

题目大意:给你一个序列,求某个区间出现次数大于一半的数是什么 主席树裸题,刷刷水题提升自信= = 1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #define ll long long 5 #define il inline 6 #define N 500100 7 using namespace std; 8 //re 9 int n,m,tot; 10 int a[N],root[

P3567 [POI2014]KUR-Couriers 主席树

这个题比一般主席树还要简单,但是用来练习主席树再好不过了,在这里我再放一下主席树板子. 代码: #include<iostream> #include<cstdio> #include<cmath> #include<ctime> #include<queue> #include<algorithm> #include<cstring> using namespace std; #define duke(i,a,n) fo

3524: [Poi2014]Couriers -- 主席树

3524: [Poi2014]Couriers Time Limit: 20 Sec  Memory Limit: 256 MB Description 给一个长度为n的序列a.1≤a[i]≤n.m组询问,每次询问一个区间[l,r],是否存在一个数在[l,r]中出现的次数大于(r-l+1)/2.如果存在,输出这个数,否则输出0. Input 第一行两个数n,m.第二行n个数,a[i].接下来m行,每行两个数l,r,表示询问[l,r]这个区间. Output m行,每行对应一个答案. Sample

bzoj3524 [Poi2014]Couriers/2223 [Coci 2009]PATULJCI

题目链接1 题目链接2 主席树模板题 两题有细节不同 1 #include<algorithm> 2 #include<iostream> 3 #include<cstdlib> 4 #include<cstring> 5 #include<cstdio> 6 #include<string> 7 #include<cmath> 8 #include<ctime> 9 #include<queue>

【复习笔记】主席树

昨天在写带修改主席树的时候,咸鱼zcysky发现自己似乎根本不会写主席树 于是正好找个空复习下-- 主席树的原理不用我扯了,主席树为啥能求k大,大概在它可以用历史版本存下区间的前缀和,求的时候差分下就能提出我要求的区间. 不过这么搞的话不要忘了离散化. 1.kth number 就是上面的裸题,不要手贱写bits就好. 1 #include<iostream> 2 #include<cstdio> 3 #define N 100010 4 #include<algorithm

【算法】主席树

这是一篇有关主席树的总结 主席树是什么? 对于原序列的每一个前缀[1···i]建立出一棵线段树维护值域上每个数出现的次数,则其树是可减的 PS:本篇随笔对于主席树的基本内容并没有深刻讲解,主要说明它的一些用法 其实就是很多一堆大量的权值线段树 (什么是权值线段树?就是每个节点维护不是位置,而是权值,比如 \([1,4]\) 维护的就是权值等于1到权值等于4的信息) 而且这些线段树还隐含了一个前缀和的功能 最简单的就是一个数列,长度为 \(n\) ,那么就建 \(n\) 棵权值线段树,第 \(i\