首页 > 其他分享 >题解 P2839【[国家集训队] middle】

题解 P2839【[国家集训队] middle】

时间:2023-07-16 11:00:14浏览次数:39  
标签:node cnt return leq int 题解 mid middle 国家集训队

Problem

一个长度为 \(n\) 的序列 \(a\),设其排过序之后为 \(b\),其中位数定义为 \(b_{n/2}\),其中 \(a,b\) 从 \(0\) 开始标号,除法下取整。

给你一个长度为 \(n\) 的序列 \(s\)。

回答 \(Q\) 个这样的询问:\(s\) 的左端点在 \([a,b]\) 之间,右端点在 \([c,d]\) 之间的子区间中,最大的中位数。

其中 \(a<b<c<d\)。

位置也从 \(0\) 开始标号。

我会使用一些方式强制你在线。

对于 \(100\%\) 的数据,\(1\leq n \leq 20000\),\(1\leq Q \leq 25000\),\(1\leq a_i\leq 10 ^ 9\)。

Solution

如果 \(q=1\)。

我们很开心地二分 \(x\),将 \(<x\) 的标成 \(-1\),将 \(\geq x\) 的标成 \(1\),那么我只需要找是否存在一个区间和 \(\geq 0\) 就行了!

因为 \(b<c\),我们前缀和,找 \([a-1,b-1]\) 最小的和 \([c,d]\) 最大的相减,如果这都不行那就不行了。

现在 \(q\leq 50000\),非常生气,考虑静态维护一下前缀和,发现可以按照值分成 \(n\) 个版本,两两之间相差一个值(\(1\to -1\)),对应的是区间加。询问是区间 \(\min/\max\)。

可持久化线段树,但是标记永久化。

(标记永久化就是说线段树上的标记不下传,每个节点上的 \(ans\) 只关心自己子树的标记和答案之和,询问时加上祖先的)

Code

点击查看代码

#include <cstdio>
#include <vector>
#include <cstring>
#include <cassert>
#include <algorithm>
using namespace std;
#ifdef LOCAL
#define debug(...) fprintf(stderr,##__VA_ARGS__)
#else
#define debug(...) void(0)
#endif
typedef long long LL;
struct node{
	int mn,mx;
	node operator+(int k){return node{mn+k,mx+k};}
	node operator*(node b){return node{min(mn,b.mn),max(mx,b.mx)};}
};
template<int N> struct segtree{
	node ans[N<<5]; int tag[N<<5],ch[N<<5][2],tot;
	int newnode(int p=0){int q=++tot;return memcpy(ch[q],ch[p],sizeof ch[0]),ans[q]=ans[p],tag[q]=tag[p],q;}
	segtree():tot(0){ch[0][0]=ch[0][1]=0,ans[0]=node{0,0},tag[0]=0;}
	void maintain(int p){ans[p]=ans[ch[p][0]]*ans[ch[p][1]]+tag[p];}
	int build(int l,int r){
		int p=newnode();
		if(l==r) return ans[p]={l,l},tag[p]=l,p;
		int mid=(l+r)>>1;
		ch[p][0]=build(l,mid),ch[p][1]=build(mid+1,r);
		maintain(p);
		return p;
	}
	int modify(int k,int L,int R,int p,int l,int r){
		int q=newnode(p);
		if(L<=l&&r<=R) return ans[q]=ans[q]+k,tag[q]+=k,q;
		int mid=(l+r)>>1;
		if(L<=mid) ch[q][0]=modify(k,L,R,ch[p][0],l,mid);
		if(mid<R) ch[q][1]=modify(k,L,R,ch[p][1],mid+1,r);
		maintain(q);
		return q;
	}
	node query(int L,int R,int p,int l,int r){
		if(L<=l&&r<=R) return ans[p];
		int mid=(l+r)>>1;
		if(L<=mid&&mid<R) return query(L,R,ch[p][0],l,mid)*query(L,R,ch[p][1],mid+1,r)+tag[p];
		if(L<=mid) return query(L,R,ch[p][0],l,mid)+tag[p];
		if(mid<R) return query(L,R,ch[p][1],mid+1,r)+tag[p];
		return assert(0),node{};
	}
};
template<int N> struct flower{
	int b[N+10],cnt;
	flower():cnt(0){}
	void add(int x){b[++cnt]=x;}
	void build(){sort(b+1,b+cnt+1),cnt=unique(b+1,b+cnt+1)-b-1;}
	int operator()(int x){return lower_bound(b+1,b+cnt+1,x)-b;}
	int operator[](int x){return b[x];}
};
int n,Q,a[1<<16],root[1<<16];
flower<1<<16> b;
segtree<1<<16> t;
vector<int> pos[1<<16];
int binary(int L,int R,int l1,int r1,int l2,int r2){
	int ans=0;
	bool flag=0;
	if(!l1) flag=1,l1=1;
	for(int mid=(L+R)>>1;L<=R;mid=(L+R)>>1){
		int lmn=t.query(l1,r1,root[mid],1,n).mn;
		if(lmn>0&&flag) lmn=0;
		int rmx=t.query(l2,r2,root[mid],1,n).mx;
		debug("mid=%d,mn[%d,%d,flag=%d]=%d,mx[%d,%d]=%d\n",mid,l1,r1,flag,lmn,l2,r2,rmx);
		if(rmx>=lmn) ans=mid,L=mid+1;
		else R=mid-1;
	}
	return ans;
}
int main(){
//	#ifdef LOCAL
//	 	freopen("input.in","r",stdin);
//	#endif
	scanf("%d",&n);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]),b.add(a[i]);
	b.build();
	for(int i=1;i<=n;i++) pos[a[i]=b(a[i])].push_back(i);
	root[0]=t.build(1,n);
	for(int i=1;i<=n;i++){
		root[i]=root[i-1];
		for(int x:pos[i-1]) root[i]=t.modify(-2,x,n,root[i],1,n);
		
		for(int j=1;j<=n;j++) debug("%d%c",t.query(j,j,root[i],1,n).mx," \n"[j==n]);
	}
	scanf("%d",&Q);
	for(int i=1,_=0;i<=Q;i++){
		vector<int> q(4);
		for(int&x:q) scanf("%d",&x),x+=_,x%=n,x++;
		sort(q.begin(),q.end());
		debug("ask(%d,%d,%d,%d)\n",q[0],q[1],q[2],q[3]);
		printf("%d\n",_=b[binary(1,n,q[0]-1,q[1]-1,q[2],q[3])]);
	}
	return 0;
}

标签:node,cnt,return,leq,int,题解,mid,middle,国家集训队
From: https://www.cnblogs.com/caijianhong/p/solution-p2839.html

相关文章

  • 你省(福建)省队集训 Day5 T1 题解
    简要题意有两个正整数\(a<b\le10^9\),给出\(\dfrac{a}{b}\)的小数点后\(19\)位,要求还原\(a,b\),保证有解。solution一个科技:\(\texttt{Stern-Brocottree}(SBT)\),可以参考这个博客学习。先给出\(O(n)\)找的代码:......
  • 云斗杯 T2 派蒙是最好的伙伴! 题解
    云斗杯T2题解赛时脑抽了只打了60pts暴力xwx。题目描述给定两个长度为\(n\)的\(01\)序列\({a_n}\)和\({b_n}\),与另一个矩阵\({c_{n,n}}\)。矩阵\({c_{n,n}}\)的生成规则如下:\[c_{i,j}=a_i\timesb_j\]现给定一个数\(k\),求在矩阵\(c_{n,n}\)内,有多少个......
  • freee Programming Contest 2023(AtCoder Beginner Contest 310)题解
    点我看题A-OrderSomethingElse直接比较\(P\)和\(Q+min(D_i)\),输出较小值即可。点击查看代码#include<bits/stdc++.h>#definerep(i,n)for(inti=0;i<n;++i)#definerepn(i,n)for(inti=1;i<=n;++i)#defineLLlonglong#definefifirst#definesesecond#defi......
  • AJAX请求,响应头有set-cookie但浏览器不能写入cookie问题解决!
    开幕雷击:AJAX就不是干这个ajax只有向服务器发送请求时带上cookie的功能可选。不存在ajax向服务器get的时候带回来cookie的功能。解决把AJAX代码改成原始的js代码来完成需求:正确的jsdocument.addEventListener('DOMContentLoaded',function(){document.querySelector('......
  • CF339 题解
    CF339题解这套题虽然是div2,但是具有一定的价值,这套题作为典型的div2题目,全套5道题都几乎用暴力方法解决,但是为什么这样是对的?令人深思。A红题,把个位数提出来再排序就好了。#include<bits/stdc++.h>usingnamespacestd;constintN=105;chars[N];intn,num[N],tot=0......
  • P1891 疯狂 LCM 题解
    一、题目描述:$T$ 组数据,每组数据给定$n$,求$\sum_{i=1}^{n}lcm(i,n)$数据范围:$1\leT\le3\times10^5,1\len\le1\times10^6$。 二、解题思路:个人觉得思维难度不大,只是要记住一个结论:$\sum_{d\midn}d=\frac{\varphi(n)\timesn}{2}$这个公式对......
  • VMware17无法连接USB设备的问题解决方案
    前言【前言都是废话,可以直接看解决方案】事情是这样的,最近在做IMX6ULL的开发,刚开始就遇到了这个拦路虎问题,我使用的闪迪的TF卡32GB的,搭配绿联的读卡器使用。在windows以及物理机装的archlinux都能正常识别并进行挂载,离谱的就是在虚拟机上识别不了。虚拟机版本:VMwareWorkstati......
  • CF1220F Gardener Alex 题解--zhengjun
    发现根节点一定是\(1\),所以考虑两边的子树深度,然后发现只需要考虑一段后缀或前缀的深度即可。所以循环位移后,可以从中间往两边构建笛卡尔树,实时维护深度即可。代码#include<bits/stdc++.h>usingnamespacestd;usingll=longlong;constintN=2e5+10;intn,a[N],ans[N];......
  • CF732E Sockets 题解
    功率是\(x\)的插座插入一个适配器后功率是\(y\),功率是\(y\)的插座插入一个适配器后功率是\(z\),那么相当于功率是\(x\)的插座插入两个适配器。一个电脑可以用功率小的插座插入较少的适配器表达,也可以用功率大的插座插入较多的适配器表达。这里功率大的插座必然能表达出功......
  • 题解 [NOIP2015 提高组] 运输计划
    题目链接闲话:虽说是紫题,但慢慢想还是完全没有问题的。由于\(m\)个运输计划同时开始,所以耗费时间就是最慢的飞船耗费的时间(即最长时间)。考虑到题目让求最短时间,也就是最长的最短,可以二分。考虑二分最长时间(记作\(k\)),那么将所有路径分成两类,一类是原来耗费的时间就小于等于\(......