扫描线 qwq

ABC327F Apples

时间一维和位置一维没什么区别,随便选一个,比如扫时间一维。用数据结构维护左上角在该位置时的答案。感觉这种维护方法以前没见过?

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<map>
#include<queue>
#include<vector>
#define lc note<<1
#define rc note<<1|1
#define mp make_pair
using namespace std;
const int N=2e5+5;
int n,d,w,tim,pos,x,y,ans;
vector<pair<int,int> > q[N];
inline int read()
{
	int s=0,t=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')t=-1;ch=getchar();}
	while(ch>='0'&&ch<='9') s=(s<<1)+(s<<3)+(ch^48),ch=getchar();
	return s*t;
}
struct Tree
{
	int left,right,tag,ma;
}s[N<<2];
inline void build(int note,int l,int r)
{
	s[note].left=l;
	s[note].right=r;
	s[note].tag=0;
	s[note].ma=0;
	if(l==r) return;
	int mid=(s[note].left+s[note].right)>>1;
	build(lc,l,mid);
	build(rc,mid+1,r);
	return;
}
inline void push_down(int note)
{
	if(!s[note].tag) return;
	s[lc].ma+=s[note].tag;
	s[rc].ma+=s[note].tag;
	s[lc].tag+=s[note].tag;
	s[rc].tag+=s[note].tag;
	s[note].tag=0;
	return;
}
inline void push_up(int note){s[note].ma=max(s[lc].ma,s[rc].ma);}
inline void modify(int note,int l,int r,int qwq)
{
	if(l<=s[note].left&&s[note].right<=r)
	{
		s[note].ma+=qwq;
		s[note].tag+=qwq;
		return;
	}
	push_down(note);
	int mid=(s[note].left+s[note].right)>>1;
	if(l<=mid) modify(lc,l,r,qwq);
	if(r>mid) modify(rc,l,r,qwq);
	push_up(note);
	return;
}
int main()
{
	//freopen("a.in","r",stdin);
	//freopen("a.out","w",stdout);
	n=read();
	d=read();
	w=read();
	for(int i=1;i<=n;++i)
	{
		tim=read();
		pos=read();
		q[max(1,tim-d+1)].push_back(mp(pos,1));
		q[tim+1].push_back(mp(pos,-1));
		x=max(x,tim);
		y=max(y,pos);
	}
	build(1,1,y);
	for(int i=1;i<=x;++i)
	{
		int sz=q[i].size();
		for(int j=0;j<sz;++j)
		{
			int pos=q[i][j].first;
			int val=q[i][j].second;
			modify(1,max(1,pos-w+1),pos,val);
		}
		ans=max(ans,s[1].ma);
	}
	printf("%d",ans);
	return 0;
}
// 在夜里跳舞 我在夜里跳舞
// 用我支离破碎换你一刻的眷顾
// 不归的归途 不落的夜幕
// 统统陷入一场大梦之中再虚度

JOISC 2019 D2t1 Two Antennas

题目
首先, ∣ a i − a j ∣ |a_i-a_j| aiaj 的绝对值很烦,将其转换成 m a x { h i − h j , h j − h i } max\{h_i-h_j,h_j-h_i\} max{hihj,hjhi},也就是求 m a x { h i − h j } max\{h_i-h_j\} max{hihj},那么就是把贡献是 h i − h j h_i-h_j hihj 和贡献是 h j − h i h_j-h_i hjhi 各做一遍取最大值。
然后我们扫描线,考虑如何在 j j j 处找到使 h i − h j h_i-h_j hihj 最大的 i   ( i < j ) i\space(i<j) i (i<j)

a i ≤ j − i ≤ b i ⇒ a i + i ≤ j ≤ b i + i a_i\le j-i\le b_i\Rightarrow a_i+i\le j\le b_i+i aijibiai+ijbi+i
a j ≤ j − i ≤ b j ⇒ j − b j ≤ i ≤ j − a j a_j\le j-i\le b_j\Rightarrow j-b_j\le i\le j-a_j ajjibjjbjijaj

那么我们扫描线的时候,对于 i i i,在 a i + i a_i+i ai+i 处激活点 i i i 作为左端点的贡献 h i h_i hi,在 b i + i + 1 b_i+i+1 bi+i+1 处取消。
扫到 j j j 时,在区间内 [ j − b j , j − a j ] [j-b_j,j-a_j] [jbj,jaj] 内更新 j j j 作为右端点的贡献 − h j -h_j hj。然后将询问挂在 r r r 处,扫 r r r 就查一下 [ l , r ] [l,r] [l,r] 中的最大值即可。
现在的问题是如何用数据结构维护。我们考虑使用线段树维护答案的历史最大值,也就是历史最大的左端点贡献 + 右端点贡献。注意每次更新左端点时将该点右端点的贡献清零。最后对于询问就是线段树中 [ l , r ] [l,r] [l,r] 的答案。(线段树中的 [ l , r ] [l,r] [l,r] 本质就是左端点在 [ l , r ] [l,r] [l,r] 范围内的意思。)
Code

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值