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[N*20],ls[N*20],rs[N*20],n,m;
int root[N],a[N],tot;
struct A{
	int num,id,v;
}d[N];
bool cmp1(const A &x,const A &y){ return x.num<y.num; }
bool cmp2(const A &x,const A &y){ return x.id<y.id; }
void insert(int x,int &y,int l,int r,int val){
	y=++tot;
	if(l==r) { t[y] = t[x] + 1; return ; }
	int mid=l+r>>1;
	if(val<=mid) rs[y]=rs[x],insert(ls[x],ls[y],l,mid,val);
	else ls[y]=ls[x],insert(rs[x],rs[y],mid+1,r,val);
	t[y]=t[ls[y]]+t[rs[y]];
}
int query(int x,int y,int l,int r,int len){
	if(l==r) return a[l];
	int mid=l+r>>1,sizls=t[ls[y]]-t[ls[x]],sizrs=t[rs[y]]-t[rs[x]];
	if(sizls>len/2) return query(ls[x],ls[y],l,mid,len);
	if(sizrs>len/2) return query(rs[x],rs[y],mid+1,r,len);
	return 0;
}
int main()
{
	scanf("%d%d",&n,&m);
	int i,x,y,j;
	for(i=1;i<=n;i++) scanf("%d",&d[i].num),d[i].id=i;
	sort(d+1,d+n+1,cmp1);d[0].num=20003535;
	for(i=1,j=0;i<=n;i++) { if(d[i].num!=d[i-1].num)j++;d[i].v=j;a[j]=d[i].num; }
	sort(d+1,d+n+1,cmp2);
	for(i=1;i<=n;i++) insert(root[i-1],root[i],1,n,d[i].v);
	for(i=1;i<=m;i++) {
		scanf("%d%d",&x,&y);
		printf("%d\n",query(root[x-1],root[y],1,n,y-x+1));
	}
}

原文地址:https://www.cnblogs.com/suika/p/8594235.html

时间: 2024-10-08 23:35:57

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

[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&g

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

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

[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]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

【算法】主席树

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

主席树小结

https://zybuluo.com/ysner/note/1099145 标签(空格分隔): 主席树 前置技能 线段树 动态开点 标记永久化 离散化 定义 主席树=可持久化线段树=函数式线段树 线段树经过了若干次修改之后,仍然能找到原来某次修改前的线段树的信息的一种数据结构 建立 据说最无脑的方法是每修改一次新建一颗主席树??? 单点修改: 线段树单点修改只会改变\(log\)个点(一条链),主席树同理. 那为什么要新建一颗主席树呢?新建修改过的链,再同原来的点接起来,这效果不是一样的吗?

主席树|求区间第k小模板

主席树 学了主席树,用来求区间上的第k小 写一下自己整理后的模板 求区间第k小 #include<bits/stdc++.h> using namespace std; //求区间第k小 const int maxn = 500010; struct node{ int v,lc,rc; }T[maxn * 21]; int n,m; int root[maxn]; int e; void insert(int pre,int cur,int pos,int l,int r){ if(l ==