BZOJ 2653 middle 二分答案+可持久化线段树

题目大意:给定一个长度为n的序列,求当子序列s的左端点在[a,b],右端点在[c,d]时的最大中位数

其中当序列长度为偶数时中位数定义为中间两个数中较大的那个

很难想的一道题 具体题解见 http://blog.csdn.net/acm_cxlove/article/details/8566093 说的很详细

区间处理那里 [b,c]是必选的 [a,b)和(c,d]每段取最大加和 否则re恒>=0

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define M 20200
using namespace std;
struct abcd{
	int lmax,rmax,sum;
	abcd(int x=0)
	{
		lmax=rmax=max(x,0);
		sum=x;
	}
};
abcd operator + (const abcd &x,const abcd &y)
{
	abcd z;
	z.sum=x.sum+y.sum;
	z.lmax=max(x.lmax,x.sum+y.lmax);
	z.rmax=max(y.rmax,y.sum+x.rmax);
	return z;
}
struct Tree{
	Tree *ls,*rs;
	abcd seq;
}*tree[M],mempool[M*20],*C=mempool;
int n,m,ans,a[M];
pair<int,int>b[M];
Tree* New_Node(Tree *_,Tree *__,abcd ___)
{
	C->ls=_;
	C->rs=__;
	C->seq=___;
	return C++;
}
Tree* Build_Tree(int x,int y)
{
	int mid=x+y>>1;
	if(x==y)
		return New_Node( 0x0 , 0x0 , abcd(1) );
	Tree *lson=Build_Tree(x,mid);
	Tree *rson=Build_Tree(mid+1,y);
	return New_Node(lson,rson,lson->seq+rson->seq);
}
Tree *Build_Chain(Tree *p,int x,int y,int z)
{
	int mid=x+y>>1;
	if(x==y)
		return New_Node( 0x0 , 0x0 , abcd(-1) );
	if(z<=mid)
	{
		Tree *lson=Build_Chain(p->ls,x,mid,z);
		return New_Node(lson,p->rs,lson->seq+p->rs->seq);
	}
	else
	{
		Tree *rson=Build_Chain(p->rs,mid+1,y,z);
		return New_Node(p->ls,rson,p->ls->seq+rson->seq);
	}
}
abcd Get_Ans(Tree *p,int x,int y,int l,int r)
{
	int mid=x+y>>1;
	if(x==l&&y==r)
		return p->seq;
	if(r<=mid) return Get_Ans(p->ls,x,mid,l,r);
	if(l>mid) return Get_Ans(p->rs,mid+1,y,l,r);
	return Get_Ans(p->ls,x,mid,l,mid) + Get_Ans(p->rs,mid+1,y,mid+1,r);
}
bool Judge(int A,int B,int C,int D,int x)
{
	int re=0;
	re+=Get_Ans(tree[x],1,n,B,C).sum;
	re+=Get_Ans(tree[x],1,n,A,B-1).rmax;
	re+=Get_Ans(tree[x],1,n,C+1,D).lmax;
	return re>=0;
}
int Bisection(int A,int B,int C,int D)
{
	int l=1,r=n;
	while(l+1<r)
	{
		int mid=l+r>>1;
		if( Judge(A,B,C,D,mid) )
			l=mid;
		else
			r=mid;
	}
	if( Judge(A,B,C,D,r) )
		return r;
	return l;
}
int main()
{
	int i,j,q[10];
	cin>>n;
	for(i=1;i<=n;i++)
		scanf("%d",&b[i].first),b[i].second=i;
	sort(b+1,b+n+1);
	for(i=1;i<=n;i++)
		a[b[i].second]=i;
	tree[1]=Build_Tree(1,n);
	for(i=2;i<=n;i++)
		tree[i]=Build_Chain(tree[i-1],1,n,b[i-1].second);
	cin>>m;
	for(i=1;i<=m;i++)
	{
		for(j=0;j<4;j++)
			scanf("%d",&q[j]),q[j]=(q[j]+ans)%n+1;
		sort(q,q+4);
		printf("%d\n", ans=b[Bisection(q[0],q[1],q[2],q[3])].first );
	}
}
时间: 2024-11-07 10:56:33

BZOJ 2653 middle 二分答案+可持久化线段树的相关文章

BZOJ 3123 SDOI 2013 森林 可持久化线段树+启发式合并

题目大意:给出一个森林,每个节点都有一个权值.有若干加边操作,问两点之间路径上的第k小权值是多少. 思路:这题和COT1比较像,但是多了连接操作.这样就只能暴力合并连个树.启发式合并会保证时间复杂度不至于太大.然后就是用可持久化线段树维护一个树的信息,按照dfs序来建树,每个节点的可持久化链的参考版本就是它父亲的版本.之后利用权值线段树可区间加减的特性,用f[x] + f[y] - f[lca] - f[father[lca]]来计算权值. CODE: #include <cstdio> #i

BZOJ 3932 CQOI2015 任务查询系统 可持久化线段树

题目大意见http://pan.baidu.com/s/1o6zajc2 主席树裸上就好了... #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define M 100100 using namespace std; struct Segtree{ Segtree *ls,*rs; int size; long long sum; void* op

【BZOJ-2653】middle 可持久化线段树 + 二分

2653: middle Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 1298  Solved: 734[Submit][Status][Discuss] Description 一个长度为n的序列a,设其排过序之后为b,其中位数定义为b[n/2],其中a,b从0开始标号,除法取下整. 给你一个长度为n的序列s. 回答Q个这样的询问:s的左端点在[a,b]之间,右端点在[c,d]之间的子序列中,最大的中位数. 其中a<b<c<d. 位置

BZOJ 2527 Poi2011 Meteors 整体二分+线段树 / 可持久化线段树(MLE)

题目大意:给定一个环,每个节点有一个所属国家,k次事件,每次对[l,r]区间上的每个点点权加上一个值,求每个国家最早多少次操作之后所有点的点权和能达到一个值 首先我们考虑暴力想法 对于每个国家分开讨论 二分操作次数 但是这样每次Judge的时候我们要模拟1~mid所有的操作 浪费在这里的复杂度实在太大 这样做每个国家需要模拟O(klogk)次操作 时间复杂度O(nklogk) TLE 我们需要对浪费在这里的复杂度做一些改进 1.可持久化线段树(MLE) 每次二分一个mid之后 我们要找到mid次

BZOJ 2653: middle

2653: middle Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 1536  Solved: 855[Submit][Status][Discuss] Description 一个长度为n的序列a,设其排过序之后为b,其中位数定义为b[n/2],其中a,b从0开始标号,除法取下整. 给你一个长度为n的序列s. 回答Q个这样的询问:s的左端点在[a,b]之间,右端点在[c,d]之间的子序列中,最大的中位数. 其中a<b<c<d. 位置

BZOJ 2653 middle 题解

题意:一个长度为n的序列a,设其排过序之后为b,其中位数定义为b[n/2],其中a,b从0开始标号,除法取下整. 给一个序列,并进行一些询问.每次询问起点在[a,b],终点在[c,d]的序列的中位数. 题解:首先有一个思路:对于一个序列S,假设它的中位数是m,则S中>=m的元素个数一定>=n 那么对于一个序列S和一个数m,我们将>=m的元素设置为1,其余为-1,得到一个新数列S‘.则$\sum S'$ >=0 对于每个询问我们二分一下m即可.如果在区间[a,d]内有一段包含[b,c

BZOJ 3524 [Poi2014]Couriers 可持久化线段树

题意:链接 方法:可持久化线段树. 解析: 可持久化数据结构好神啊,感觉都好玄妙的感觉. 首先建树的目的就是建立一棵权值树,维护的是在L,R里某些权值的数的出现个数.然后呢,对于1~n每个节点建一棵树,并且是基于前一棵树的基础上的.然后对于每一次的新值我们只需要update一次,并且连接一下原来的树? 神犇们不是说这种结构就是一堆线段树连啊连就出来了吗. 查询的时候呢?有一些小改变,据说是以二分为基础的查询. 神犇们发明这种数据结构的时候,就发现了这种数据结构里的所有线段树是可以相减的这种性质,

Codeforces 484E Sign on Fence(可持久化线段树+二分)

题目链接:Codeforces 484E Sign on Fence 题目大意:给定给一个序列,每个位置有一个值,表示高度,现在有若干查询,每次查询l,r,w,表示在区间l,r中, 连续最长长度大于w的最大高度为多少. 解题思路:可持久化线段树维护区间合并,前端时间碰到一题可持久化字典树,就去查了一下相关论文,大概知道了是 什么东西. 将高度按照从大到小的顺序排序,然后每次插入一个位置,线段树维护最长连续区间,因为插入是按照从大到小的顺 序,所以每次的线段树中的连续最大长度都是满足高度大于等于当

[BZOJ 3207] 花神的嘲讽计划Ⅰ【Hash + 可持久化线段树】

题目链接:BZOJ - 3207 题目分析 先使用Hash,把每个长度为 k 的序列转为一个整数,然后题目就转化为了询问某个区间内有没有整数 x . 这一步可以使用可持久化线段树来做,虽然感觉可以有更简单的做法,但是我没有什么想法... 代码 #include <iostream> #include <cstdio> #include <cstdlib> #include <algorithm> #include <cstring> #inclu