首页 > 其他分享 >题解:P10590 磁力块

题解:P10590 磁力块

时间:2024-09-26 10:13:25浏览次数:1  
标签:磁铁 P10590 结点 le int 题解 read vector 磁力

\(\text{Link}\)

来自传奇讨论区大神 @年年有年 的 \(O(n\log n)\) 做法!

题意

有 \(n+1\) 块磁铁 \(0\sim n\),每个磁铁都有四个属性 \((d_i,m_i,p_i,r_i)\),如果你拥有了磁铁 \(i\),那么你就能吸引并拥有所有满足 \(d_j\le r_i,m_j\le p_i\) 的磁铁 \(j\),初始你只拥有磁铁 \(0\),求最后你能得到多少的磁铁。

\(n\le 2.5\times 10^5\)。

思路

考虑我们 BFS 中要求出满足两维偏序限制的还未被拥有过的磁铁,则预先对一维排序,另一维使用数据结构维护。

具体做法为,我们对线段树每个结点维护一个 vector,初始按 \(m\) 从小到大排序,将 \(i\) push_back 至所有包含 \(d_i\) 的结点,这样每个结点的 vector 中的下标就满足其 \(m\) 值是递增的。对每个结点维护一个指针 \(u\) 表示这个结点的 vector 的前 \(u\) 个磁铁都已经访问过,搜一个磁铁 \(i\) 能更新的磁铁时直接在 \([1,r_i]\) 所拆出的所有结点上不断增加指针直至其对应 \(m\) 值大于 \(p_i\) 即可。

所有 vector 的大小和为 \(O(n\log n)\),指针只会后移,所以时间复杂度为 \(O(n\log n)\)。

参考代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
namespace IO{//by cyffff
    
}
const int N=2.5e5+10;
int n,x[N],y[N],m[N],p[N],r[N],d[N],tp[N];
bool vis[N];
vector<ll>lsh;
inline ll dis(int i,int j){
	return 1ll*(x[i]-x[j])*(x[i]-x[j])+1ll*(y[i]-y[j])*(y[i]-y[j]);
}
inline bool cmp(int i,int j){
	return m[i]<m[j];
}
queue<int>q;
struct Segment_Tree{
	#define ls (rt<<1)
	#define rs (rt<<1|1)
	int id[N<<2];
	vector<int>vec[N<<2];
	inline void ins(int rt,int l,int r,int p,int v){
		vec[rt].push_back(v);
		if(l==r) return ;
		int mid=l+r>>1;
		if(p<=mid) ins(ls,l,mid,p,v);
		else ins(rs,mid+1,r,p,v);
	}
	inline void upd(int rt,int l,int r,int L,int R,int w){
		if(id[rt]==vec[rt].size()) return ;
		if(L<=l&&r<=R){
			while(id[rt]<vec[rt].size()&&m[vec[rt][id[rt]]]<=w){
				if(!vis[vec[rt][id[rt]]]) q.push(vec[rt][id[rt]]),vis[vec[rt][id[rt]]]=1;
				id[rt]++;
			}
			return ;
		}
		int mid=l+r>>1;
		if(L<=mid) upd(ls,l,mid,L,R,w);
		if(R>mid) upd(rs,mid+1,r,L,R,w);
	}
}T;
int main(){
	x[0]=read(),y[0]=read(),p[0]=read(),r[0]=read();
	n=read();
	lsh.push_back(0);
	for(int i=1;i<=n;i++)
		x[i]=read(),y[i]=read(),m[i]=read(),p[i]=read(),r[i]=read(),
		lsh.push_back(dis(0,i)),tp[i]=i;
	sort(lsh.begin(),lsh.end());
	lsh.erase(unique(lsh.begin(),lsh.end()),lsh.end());
	int c=lsh.size()-1; 
	for(int i=0;i<=n;i++)
		d[i]=lower_bound(lsh.begin(),lsh.end(),dis(0,i))-lsh.begin(),
		r[i]=upper_bound(lsh.begin(),lsh.end(),1ll*r[i]*r[i])-lsh.begin()-1;
	sort(tp+1,tp+n+1,cmp);
	for(int i=1;i<=n;i++)
		T.ins(1,1,c,d[tp[i]],tp[i]);
	q.push(0);
	while(!q.empty()){
		int x=q.front();
		q.pop();
		T.upd(1,1,c,1,r[x],p[x]);
	}
	int ans=0;
	for(int i=1;i<=n;i++)
		ans+=vis[i];
	write(ans);
	flush();
}

标签:磁铁,P10590,结点,le,int,题解,read,vector,磁力
From: https://www.cnblogs.com/cyffff/p/18432909

相关文章

  • 题解:CF1799F Halve or Subtract
    \(\text{Link}\)介绍一下一种高维wqs的方法。此方法来自@YeahPotato的专栏严谨的WQS二分方法。题意给定一个长为\(n\)的序列\(v_{1\dotsn}\),三个常数\(d,a,b\)。你可以执行若干次以下两种操作:选择\(1\lei\len\),令\(v_i\gets\lceil\frac{v_i}{2}\rceil\)。......
  • 勇攀山丘小队(翻越篇)1——题解
    前言胸有丘壑,气吞山河。正片A题:考虑使用DP,由于题目给了2个a不能在一起的限制,所以每次接上一个a都要考虑一下前面的一个状态是否也是a。于是就可以使用\(f,g\)数组,\(f_i\)表示第\(i\)个字母是a的合法情况有多少,\(g_i\)表示第\(i\)个字母是b或c的合法......
  • P8907 [USACO22DEC] Making Friends P 题解
    P8907[USACO22DEC]MakingFriendsP题解我们考虑维护每个\(i\),在\(i\)的后面有多少个点和它有朋友关系。初步的想法是每删掉一个人就给集合里所有的点连边。但是我们发现这样太不优了,有很多边会重复连很多次。优化的想法是对于\(i\),删去之后连的边就成了一个完全图,于是......
  • [GYM103119K][2020 ICPC Asia Macau] Candy Ads 题解
    题意简述有\(n\)个广告,每个广告在一个时间段内占据二维平面的矩形,\(m\)个约束表示两个广告至少有一个要被选择,选择若干广告,满足所有约束且同时刻不能有重叠的广告。Kosaraju算法流程在正图上跑一遍DFS,给每个位置打上时间戳从时间戳大到小枚举点,在反图上跑DFS,这个时候对......
  • 题解 洛谷P3398 仓鼠找 sugar
    原题链接:P3398仓鼠找sugar题解里大部分都是用的lca,然而我看不懂那些关于lca的性质是怎么证明出来的。不过这题可以直接用树链剖分来写,把模板套上去就好了。题意为查找两条路径是否存在公共点,我们只需要把其中一条路径上的点都赋值为1,然后查询另一条路径上的点的总和,如果总和......
  • [ARC062F] AtCoDeerくんとグラフ色塗り 题解
    思路对于一个点双,我们可以发现:假如它是一个简单环,那么它只能旋转这一个环,我们可以使用polya定理计算。假如它是多个环的组成,那么它的颜色可以随意调动,任何的情况都可以得到,那么假如说有\(m\)条边,方案数则为\(\binom{m+k-1}{k-1}\),我们只考虑每一种颜色的出现次数。对于......
  • 题解 QOJ5034【>.<】/ BC2401D【可爱路径】
    必可赛前公益众筹赛第一试Dhttps://qoj.ac/problem/5034,2022-2023集训队互测Round6(Nov12,2022)题目描述这原本是一道简单的最短路问题,但是由于种种地域文化,宗教信仰以及政治因素,原来一些或许可以行走的路径不能通行了。我们定义禁止路径为连续的经过一些特定的点的......
  • Luogu_P10977(AcWing_299) Cut the Sequence 题解
    解题思路考虑线性dp。首先如果存在\(a_i>m\),那肯定不满足条件,输出\(-1\)。设\(f_i\)表示前\(i\)个数分成若干段,然后每段最大数之和,其中每段内的整数之和不超过\(m\)。\(f_i\)肯定是由\(f_j\)(\(1\lej<i\))转移过来的,也就是前\(j\)个数分好后再加上\((j,i]\)这一......
  • 【OJ题解-1】稀疏矩阵乘法
    一、试题题面计算两个稀疏矩阵相乘,输出相乘的结果【输入输出约定】输入:第一行输入三个正整数p、q、r,表示p×q和q×r的两个矩阵相乘;(约定0<p,q,r≤1000)然后是第一个矩阵的输入,首先是一个整数m,表示矩阵一有m个非零元素;然后是m行,每行三个整数i,j,d,表示第i行,第j列的元素为d(约定......
  • P8906 [USACO22DEC] Breakdown P 题解
    P8906[USACO22DEC]BreakdownP题解显然的套路是删边转化为加边。考虑到维护整条路径不好维护,于是考虑转化维护\(f_{i,k},g_{i,k}\)分别表示\(1,n\)到\(i\)走了\(k\)步时的最短路。那么此时\(k\le4\)。我们先考虑\(f\)的转移,\(g\)的转移是等价的。那么对于\((......