首页 > 其他分享 >CF-522-D-线段树

CF-522-D-线段树

时间:2024-05-05 13:56:01浏览次数:10  
标签:nxt le int 线段 元素 CF vector 522

522-D 题目大意

给定一个长为\(n\)的序列\(a\),现有\(q\)个查询,每个查询\(q_i\)给定\(l_i,r_i(1 \le l_i,r_i \le n)\),要你找出所有相等元素对\(a_x\)和\(a_y(l_i \le x,y \le r_i)\)中,绝对值\(|x-y|\)的最小值。


Solution

考虑三个相等的元素\(a_x,a_y,a_z(x < y < z)\),对于一个区间包含这三个元素的询问,我们只需要考虑\(|x-y|\)和\(|z-y|\)的大小,可以直接舍弃掉\(|z-x|\),由此我们可以注意到,只需要关注相等元素那些相邻的元素对即可。那么基于此,整个序列中最多只会有\(n-1\)的元素对需要考虑。

那么如何维护这写元素对对应的线段长度来回答询问呢?

一个朴素的想法是把询问离线下来,按左端点排序,扫描线处理。线段长度则这样维护,把每个点作为左端点时的对应的最短线段长度记录下来,然后整体丢到一个数据结构里面。扫描的时候,把扫过点对应的信息从数据结构里删除,回答询问的时候从集合里查询区间最小值。显然,可以用线段树来实现它。

剩下的只需要预处理出各个元素作为左端点时对应的右端点,再全部插入线段树中即可。

时间复杂度\(O(nlog^2n)\),预处理有一个离散化,因此是双\(log\)的。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int N=5e5+10;
struct node{
	int l,r;
	int w;
}tr[N<<2];

void build(int u,int l,int r){
	tr[u]={l,r,(int)1e9};
	if(l==r) return;
	int m=(l+r)>>1;
	build(u<<1,l,m);
	build(u<<1|1,m+1,r);
}

void modify(int u,int l,int r,int k){
	if(l<=tr[u].l&&tr[u].r<=r){
		tr[u].w=k;
		return;
	}
	int m=(tr[u].l+tr[u].r)>>1;
	if(l<=m) modify(u<<1,l,r,k);
	if(r>m) modify(u<<1|1,l,r,k);
	tr[u].w=min(tr[u<<1].w,tr[u<<1|1].w);
}

int query(int u,int l,int r){
	if(l<=tr[u].l&&tr[u].r<=r){
		return tr[u].w;
	}
	int m=(tr[u].l+tr[u].r)>>1;
	int res=1e9;
	if(l<=m) res=min(res,query(u<<1,l,r));
	if(r>m) res=min(res,query(u<<1|1,l,r));
	return res;
}

int main(){
	ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0);
	int n,m;
	cin>>n>>m;
	vector<int> a(n);
	for(int i=0;i<n;i++) cin>>a[i];
	vector<array<int,3>> q(m);
	for(int i=0;i<m;i++){
		cin>>q[i][0]>>q[i][1];
		q[i][2]=i;
	}
	sort(q.begin(),q.end());
	map<int,int> p;
	vector<int> nxt(n,-1);
	build(1,1,n);
	for(int i=n-1;~i;i--){
		if(p.count(a[i])){
			nxt[i]=p[a[i]];
			modify(1,nxt[i]+1,nxt[i]+1,nxt[i]-i);
		}
		p[a[i]]=i;
	}
	vector<int> ans(m);
	for(int i=0,j=0;i<n;i++){
		while(j<m&&q[j][0]==i+1){
			ans[q[j][2]]=query(1,q[j][0],q[j][1]);
			j++;
		}
		if(nxt[i]!=-1) modify(1,nxt[i]+1,nxt[i]+1,1e9);
	}
	for(int i=0;i<m;i++){
		if(ans[i]==1e9) ans[i]=-1;
		cout<<ans[i]<<'\n';
	}
	return 0;
}

标签:nxt,le,int,线段,元素,CF,vector,522
From: https://www.cnblogs.com/fengxue-K/p/18173452

相关文章

  • CF729B Spotlights 题解
    题目简述给出一个$n$行$m$列的$01$矩阵,定义每个点的价值为上下左右四个方向有$1$的方向数,求所有为$0$的点的价值和。题目分析我们首先可以考虑暴力,但是发现是不行的。于是我们考虑动态规划。设$dp_{i,j,0/1/2/3}$分别表示$(i,j)$这个点上方,左方,下方,右方是否有$......
  • CF-877-E-dfs序+线段树
    877-E题目大意给定一颗\(n\)个节点的树,根为\(1\),点带权,权值要么为0,要么为1。\(q\)次询问,两种类型:\(get\spacex\):询问\(x\)的子树中有多少个\(1\)。\(pow\spacex\):将\(x\)子树中所有的值取反。Solutiondfs序+线段树模板题,把子树上的操作转化为区间上的操作。时间......
  • 线段树--RMQ
    这是带上lazy标记的线段树板子inta[N];intls(intp){returnp<<1;}intrs(intp){returnp<<1|1;}classSegmentTree{public: inttree[N<<2|1],tag[N<<2|1]; inlinevoidpush_up(intp){ tree[p]=tree[ls(p)]+tree[rs(p)]; } in......
  • 算法随笔——主席树(可持久化线段树)
    介绍主席树即可持久化线段树,由hjt大佬发明。好像又称函数式线段树。可以查询序列在任意时间的历史状态。学习链接学习链接主要思路维护历史状态,若采用直接拷贝整棵树的方式,空间爆炸。可以发现每次修改只有部分节点发生了改变(其实就是到树根那条链会改变),因此每次只需要记......
  • CF-600-E-启发式合并
    600-E题目大意给定一颗\(n\)个节点的树,根为\(1\)。树上的每个节点\(i\)都有一个颜色\(c_i\)。如果一个颜色在以\(x\)为根的子树中出现次数最多,那么称该颜色为主要颜色,显然,一颗树中可以有多个主要颜色。求出对于每个节点为根时,其子树中所有主要颜色的编号和。Solution启发式......
  • CF-797-E-根号分治
    797-E题目大意给定一个长为\(n\)序列\(a\),有\(q\)次询问:给定\(p,k\),你需要反复执行操作\(p=p+a_p+k\),直到\(p>n\)为止,问你要执行多少次操作。Solution考虑两种思路:1、暴力回答询问,每次反复模拟操作,直到\(p>n\)为止,时间复杂度\(O(q·\frac{n}{k})\)。2、预处理出......
  • CF1968E.Cells Arrangement-构造(给个和题解不同的做法)
    link:https://codeforces.com/problemset/problem/1968/E题意:需要构造一个\(n\timesn\)的棋盘,在上面放\(n\)枚棋子,设集合\(\mathcal{H}\)表示两两之间曼哈顿距离构成的集合,要让\(|\mathcal{H}|\)最大。给出放棋子的方案。首先说说题解的做法…考虑把距离为奇数和偶数的......
  • CF940F.Machine Learning-带修莫队、Mex
    给一个序列\(a\),两个操作:1、给\(l,r\),设\(a_l,\dots,a_r\)这些数集中每个数\(v\)的出现次数是\(c_v\),要求\(\mathrm{mex}(c_i)\).2、单点修改\(1\leqn,q\leq10^5\),时限4s这种一眼看过去很难维护的信息,一般就先找找性质。首先注意到关键性质:要求的是出现次数......
  • 题解:CF1926G
    题目传送门思路发现权值为C的点可以选择看做是权值为S或为P的点,所以问题转换为怎么给C点赋值可以使答案最小,考虑树形dp。\(f_{i,0/i,1}\)表示\(i\)点赋值为S或P时最少要删除几条边。但如果当前点权值不为C的话,那显然他的父亲节点应该选择和他权值相同的点才......
  • CF941
    Alink其实,只要有第一次,那么下次随意找一个队列里有的数加\(k-1\)个进去,加上队列里那一个删掉\(k\)个,到最后一次肯定是剩\(k-1\)个。没有第一次,就是\(n\)。点击查看代码#include<bits/stdc++.h>usingnamespacestd;intt;intn,k;inta[105];intmp[105];voidqwq......