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|
∣ai−aj∣ 的绝对值很烦,将其转换成
m
a
x
{
h
i
−
h
j
,
h
j
−
h
i
}
max\{h_i-h_j,h_j-h_i\}
max{hi−hj,hj−hi},也就是求
m
a
x
{
h
i
−
h
j
}
max\{h_i-h_j\}
max{hi−hj},那么就是把贡献是
h
i
−
h
j
h_i-h_j
hi−hj 和贡献是
h
j
−
h
i
h_j-h_i
hj−hi 各做一遍取最大值。
然后我们扫描线,考虑如何在
j
j
j 处找到使
h
i
−
h
j
h_i-h_j
hi−hj 最大的
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
ai≤j−i≤bi⇒ai+i≤j≤bi+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
aj≤j−i≤bj⇒j−bj≤i≤j−aj
那么我们扫描线的时候,对于
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]
[j−bj,j−aj] 内更新
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