首页 > 其他分享 >整体二分

整体二分

时间:2024-05-07 17:15:10浏览次数:23  
标签:二分 qr int 陨石雨 整体 ans ql 流星雨

抽象。

P3527 [POI2011] MET-Meteors

Byteotian Interstellar Union 有 \(n​\) 个成员国。现在它发现了一颗新的星球,这颗星球的轨道被分为 \(m​\) 份(第 \(m​\) 份和第 \(1​\) 份相邻),第 \(i​\) 份上有第 \(a_i​\) 个国家的太空站。

这个星球经常会下陨石雨。BIU 已经预测了接下来 \(k\) 场陨石雨的情况。

BIU 的第 \(i\) 个成员国希望能够收集 \(p_i\) 单位的陨石样本。你的任务是判断对于每个国家,它需要在第几次陨石雨之后,才能收集足够的陨石。

sol

考虑一个函数 \(work(l,r,ql,qr).\)

函数表示欲要处理 \(ans[a[l]],ans[a[l+1]],ans[a[l+2]],\cdots,ans[a[r]].\)

现在已经可以确定这些 \(ans\) 是可以在 \(ql,qr\) 之间的。

然后考虑把整个区间 \(a\) 划分成两个区间 \([l,x],(x,r],\) 然后这两个区间的 \(ans\) 分别可以确定在 \([ql,qmid],(qmid,qr]\) 之间。然后继续递归下去。

先降下 \([ql,qmid]\) 之间的流星雨,然后处理一下流星雨的树状数组,逐个国家判断之的流星雨降落数量和 \(p[a[i]]\) 的关系。

然后如果小于用一个指针划分到左边,否则用指针划分到右边。

最后注意 \(l\) 的区间分治过程中要回溯(把之前降下的流星雨给升回去)。

然后最后为了判断无解情况要多加一次流星雨。

程式
#include <bits/stdc++.h>
#define Add emplace_back
typedef long long ll;
using std::cin;
using std::cout;
const int N=3e5+10;
ll a[N],b[N],c[N];
int p[N],ans[N];
int n,m,k;
inline int lb(int x){ return x&-x; }
inline void add(int x,int k){ while(x<=m) c[x]+=k, x+=lb(x); }
inline ll qry(int l){
	ll ans=0;
	while(l) ans+=c[l], l-=lb(l);
	return ans;
}
inline void addr(int l,int r,int k){ add(l,k), add(r+1,-k); }
struct rrr{ int l,r,v; } rain[N];
inline void upd(int i,int zf){
	if(rain[i].l<=rain[i].r) addr(rain[i].l,rain[i].r,rain[i].v*zf);
	else addr(1,rain[i].r,rain[i].v*zf), addr(rain[i].l,m,rain[i].v*zf);
}
std::vector<int> v[N];
void work(int l,int r,int ql,int qr){
	if(ql==qr||l>r) {
		for(int i=l;i<=r;++i) ans[a[i]]=ql;
		return;
	}
	int midc=(l+r)>>1,midq=(ql+qr)>>1;
	for(int i=ql;i<=midq;++i) upd(i,1);
	int lft=l,rgt=r;
	for(int i=l;i<=r;++i){
		ll R=0;
		for(int x:v[a[i]]){
			R+=qry(x);
			if(R>=p[a[i]]) break;
		}
		if(R>=p[a[i]]) b[lft++]=a[i];
		else b[rgt--]=a[i];
	}
	for(int i=l;i<=r;++i) a[i]=b[i];
	work(lft,r,midq+1,qr);
	for(int i=ql;i<=midq;++i) upd(i,-1);
	work(l,rgt,ql,midq);
}
// l r country ql qr rain
int main(){
	std::ios::sync_with_stdio(0);
	cin.tie(0), cout.tie(0);
	cin>>n>>m;
	for(int i=1,tmp;i<=m;++i) cin>>tmp, v[tmp].Add(i);
	for(int i=1;i<=n;++i) cin>>p[i],a[i]=i;
	cin>>k;
	for(int i=1;i<=k;++i) cin>>rain[i].l>>rain[i].r>>rain[i].v;
	work(1,n,1,k+1);
	for(int i=1;i<=n;++i){
		if(ans[i]>k) cout<<"NIE\n";
		else cout<<ans[i]<<"\n";
	}
	return 0;
}

标签:二分,qr,int,陨石雨,整体,ans,ql,流星雨
From: https://www.cnblogs.com/chihirofujisaki/p/18177794/2024_5_7

相关文章

  • 整体开发流程
    1、需求阶段需求调研MRD产出收集需求,理解需求需求评审1、PRD评审RD与PM一起参与需求评审,要清楚的知道需求的背景和收益,如没有收益需要提出挑战。业务提出的需求,要让业务一起参与。对开发点进行分析和讨论。对不合理点要主动提出,尽可能的提出解决的建议。任何需求RD同学......
  • 《代码随想录》-2.二分查找
    前提:1.有序2.无重复//版本1intleft=0;intright=nums.size()-1;while(left<=right){intmiddle=left+(right-left)/2;//防止溢出if(nums[middle]>target){right=milddle-1;}elseif(nums[middle]<target{left=middle+1;}else{returnmiddle;......
  • 整体二分学习笔记
    最近准备学数据结构乱搞,接下来学k-dtree大致介绍可以使用整体二分解决的题目需要满足以下性质:1.询问的答案具有可二分性2.修改对判定答案的贡献互相独立,修改之间互不影响效果3.修改如果对判定答案有贡献,则贡献为一确定的与判定标准无关的值4.贡献满足交换律,结合律,具有可加......
  • 整体二分
    1概念在很多题目中,我们可以使用二分法来得出答案。但是如果说这一类题目有多次询问,并且多次询问分别二分会TLE时,我们就需要引入一个东西叫整体二分。整体二分的主要思路就是将多个查询一起解决,因此它是一种离线算法。整体二分的具体操作步骤如下:首先记\([l,r]\)为答案的......
  • 整体二分学习笔记
    1.简介在一些题目中,可能存在一些题目,对于每次询问直接二分可能会TLE,此时就要用到整体二分整体二分是一种离线的方法,适用于如下情况:询问答案具有可二分性修改对判定答案的贡献相互独立,修改之间互不影响效果修改如果对判定答案有贡献,则该贡献是一个确定的与判定标准无关......
  • 二分图染色
    二分图booldfs(intu,intc){ if(color[u]==c) returntrue; elseif(color[u]==3-c) returnfalse; color[u]=c; for(intv:graph[u]) if(!dfs(v,3-c))returnfalse; returntrue;}习题:P1330封锁阳光大学解题思路按照题目要求,每一条......
  • 注册表碎片整理是一种优化操作系统注册表的方法,旨在减少注册表文件的碎片化,从而提高系
    注册表碎片整理是一种优化操作系统注册表的方法,旨在减少注册表文件的碎片化,从而提高系统性能和响应速度。它通过重新整理和优化注册表文件的存储结构,以及压缩空闲空间等方式,来改善系统的整体表现。注册表是Windows操作系统中的核心组件之一,它存储了系统和安装的应用程序的配......
  • 整体二分
    整体二分动态排名每次二分复杂度\(O(n\logV)\),问题瓶颈在于有多次询问整体二分一种离线算法,将多个询问一起处理:条件问询可以二分修改之间互不影响修改对答案的贡献和判定次数,时间无关贡献满足结合律,交换律,可加性算法流程核心函数,处理一个区间的询问,他们的......
  • 二分的妙用
    数列分段SectionII链接:https://www.luogu.com.cn/problem/P1182题目描述对于给定的一个长度为\(N\)的正整数数列\(A_{1\simN}\),现要将其分成\(M\)(\(M\leqN\))段,并要求每段连续,且每段和的最大值最小。关于最大值最小:例如一数列\(4\2\4\5\1\)要分成\(3\)段。将......
  • 二分查找
    先给数组排序定义最小点left和最大点right取中间值作为cur循环判断,cur跟target谁更大若cur大了,则减小最大值right为cur-1;反之增加最小值为cur+1直到找到cur下标跟target一样大的情况,就可以返回cur了反之如果一直找不到,直到最小值left>最大值right了,就可以认为数组中没有这......