题解 P4647 【[IOI2007] sails 船帆】
[IOI2007] sails 船帆
怎么大家写的都是线段树/平衡树,一个树状数组不就可以搞定了么...
提供一个
首先将
设
但是这样会出现一个问题,如果直接更新
令
考虑用树状数组维护
具体地说,设树状数组为
设
以
同理,
最后求出每个
总时间复杂度为
Code:
#include<bits/stdc++.h>
typedef long long LL;
typedef long double LD;
using namespace std;
const LL N=100010,M=1000010,INF=0x3f3f3f3f;
inline LL max(LL x,LL y){return x>y?x:y;}
inline LL min(LL x,LL y){return x<y?x:y;}
inline void swap(LL &x,LL &y){x^=y^=x^=y;}
LL n,w,ans,c[N];
struct node{LL h,k;}a[N];
bool cmp(node a,node b){return a.h<b.h;}
void add(LL x,LL y){
for(;x<N;x+=x&-x)c[x]+=y;
}
LL ask(LL x){
LL res=0;
for(;x;x-=x&-x)res+=c[x];
return res;
}
void upd(LL l,LL r,LL d){
if(l>r)return;
add(l,d),add(r+1,-d);
}
int main(){
scanf("%lld",&n);
for(LL i=1;i<=n;i++)
scanf("%lld%lld",&a[i].h,&a[i].k);
sort(a+1,a+n+1,cmp);
for(LL i=1;i<=n;i++){
int h=a[i].h,k=a[i].k;
LL val=ask(h-k+1),l=0,r=0;
for(LL j=17,sum=0;j>=0;j--)
if(l+(1<<j)<=h&&sum+c[l+(1<<j)]>val)sum+=c[l+(1<<j)],l+=(1<<j);
for(LL j=17,sum=0;j>=0;j--)
if(r+(1<<j)<=h&&sum+c[r+(1<<j)]>=val)sum+=c[r+(1<<j)],r+=(1<<j);
l=max(l+1,1);r=min(r,h);w=max(w,h);
upd(r+1,h,1),upd(l,l+r-(h-k+1),1);
}
for(LL i=1;i<=w;i++){
LL p=ask(i);
ans+=p*(p-1)>>1;
}
printf("%lld\n",ans);
return 0;
}