题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1805
好久不写博客了,但是也不能老不写,对吧?于是我就随便找了这道题来水一篇。
废话少说,这题有一个很明显的贪心策略,设每个位置上的旗子数量为 Si S i ,我们先按旗杆长度从小到大排个序,每次贪心地找到可行的位置中旗子数量最少的 k k 个全部加 1 1 ,最后即为答案。时间复杂度 Θ(∑H) Θ ( ∑ H ) ,因为 ∑H ∑ H 会达到 1010 10 10 ,所以显然是过不了的。
要是使每次需要增加的 Si S i 的位置连续就好了,这样就可以直接线段树模拟了。仔细想想,这也一定是可行的,因为一定存在一种方案,使得最后的 Si S i 随着高度的增加而递减。但是怎样使 Si S i 保持这样的性质呢?我们可以这样考虑:假设 Si S i 现在有递减的性质,我们也已经知道了要修改的区间,设为 [l,r] [ l , r ] ,由于每次修改只增加 1 1 ,所以如果,直接修改不会影响递减性质,不用管;否则,也就是当 Sl−1=Sl S l − 1 = S l 时,如果让 Sl S l 加 1 1 的话就会破坏性质,这时,我们可以找到与相等的最左位置 Sl′ S l ′ 与最右位置 Sr′ S r ′ (注意, r′ r ′ 必须满足 r′≤r r ′ ≤ r ),我们将 [l,r] [ l , r ] 的修改分为两块, [l,r′] [ l , r ′ ] 和 [r′+1,r] [ r ′ + 1 , r ] ,如果将 [l,r′] [ l , r ′ ] 的修改区间平移至 [l′,l′+r′−l] [ l ′ , l ′ + r ′ − l ] ,我们会发现这样既不改变性质又不影响答案,于是就可以直接上线段树了。时间复杂度 Θ(Nlog2H) Θ ( N l o g 2 H ) 。
贴下代码撒:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
using namespace std;
namespace sgt
{
int mx[200010],mn[200010],chg[200010],son[200010][2],root,cnt;
void pushdown(int x)
{
mn[x]+=chg[x];
mx[x]+=chg[x];
if(son[x][0] && son[x][1])
{
chg[son[x][0]]+=chg[x];
chg[son[x][1]]+=chg[x];
}
chg[x]=0;
}
void pushup(int x)
{
if(!son[x][0] || !son[x][1])return;
mn[x]=mn[son[x][1]]+chg[son[x][1]];
mx[x]=mx[son[x][0]]+chg[son[x][0]];
}
void build(int &x,int l,int r)
{
x=++cnt;
mn[x]=mx[x]=chg[x]=0;
if(l==r)return;
int mid=(l+r)>>1;
build(son[x][0],l,mid);
build(son[x][1],mid+1,r);
pushup(x);
}
void update(int a,int b,int k,int l,int r)
{
if(a>b || l>r)return;
if(a==l && b==r)
{
chg[k]++;
pushdown(k);
return;
}
pushdown(k);
int mid=(l+r)>>1;
if(b<=mid)update(a,b,son[k][0],l,mid);
else if(a>mid)update(a,b,son[k][1],mid+1,r);
else
{
update(a,mid,son[k][0],l,mid);
update(mid+1,b,son[k][1],mid+1,r);
}
pushup(k);
}
int ql(int x,int l,int r,int v)
{
pushdown(x);
if(l==r)return l;
int mid=(l+r)>>1;
if(mn[son[x][0]]+chg[son[x][0]]>v)return ql(son[x][1],mid+1,r,v);
else return ql(son[x][0],l,mid,v);
}
int qr(int x,int l,int r,int v)
{
pushdown(x);
if(l==r)return l;
int mid=(l+r)>>1;
if(mx[son[x][1]]+chg[son[x][1]]<v)return qr(son[x][0],l,mid,v);
else return qr(son[x][1],mid+1,r,v);
}
int query(int x,int l,int r,int v)
{
pushdown(x);
if(l==r)return mn[x];
int mid=(l+r)>>1;
if(v<=mid)return query(son[x][0],l,mid,v);
else return query(son[x][1],mid+1,r,v);
}
long long calc(int x,int l,int r)
{
pushdown(x);
if(l==r)return 1LL*mn[x]*(mn[x]-1)/2LL;
int mid=(l+r)>>1;
return calc(son[x][0],l,mid)+calc(son[x][1],mid+1,r);
}
}
int n;
pair<int,int>q[100010];
int h;
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d%d",&q[i].first,&q[i].second),h=max(h,q[i].first);
sort(q+1,q+n+1);
sgt::build(sgt::root,1,h);
for(int i=1;i<=n;i++)
{
int val=sgt::query(sgt::root,1,h,q[i].first-q[i].second+1);
int l=sgt::ql(sgt::root,1,h,val),r=min(q[i].first,sgt::qr(sgt::root,1,h,val));
sgt::update(l,l+r-(q[i].first-q[i].second+1),sgt::root,1,h);
sgt::update(r+1,q[i].first,sgt::root,1,h);
}
printf("%lld",sgt::calc(sgt::root,1,h));
return 0;
}