[IOI2007] sails 船帆

[IOI2007] sails 船帆

线段树或者其他数据结构维护贪心

分析问题,其实就是要合理安排旗子使得每一行的旗子个数较平均,答案就是\(\sum{cnt[i]*(cnt[i]-1)/2}\)

考虑高度较低的旗杆放旗子比较不灵活(?),所以我们先让较低的放,不齐的由较高的旗杆补

对于\(h,k\),我们按照\(h\)递增排序,问题转化为对于\(1-h\)中最小的\(k\)个位置放旗子

显然不能暴力找最小的\(k\)个位置,但是我们可以在处理的过程中保证旗子的个数在\(1-h\)上呈递减,这样就不用考虑最小的k个难找了

如何保证递减呢?

因为每次操作只会改变\(1\),所以我们先找到\(h-k+1,h\)中最小的值\(x\),以及这个值出现的最左、右位置\(L,R\)

只要将\([R+1,h],[L,L+(k-(h-R))+1]\)这两部分+1,即可保证单调性

#include<bits/stdc++.h>
using namespace std;
 
#define reg register
typedef long long ll;
#define rep(i,a,b) for(reg int i=a,i##end=b;i<=i##end;++i)
#define drep(i,a,b) for(reg int i=a,i##end=b;i>=i##end;--i)
 
inline void cmax(int &a,int b){ ((a<b)&&(a=b));} 
inline void cmin(int &a,int b){ ((a>b)&&(a=b));} 
 
 
char IO;
int rd(){
    int s=0,f=0;
    while(!isdigit(IO=getchar())) f|=(IO=='-');
    do s=(s<<1)+(s<<3)+(IO^'0');
    while(isdigit(IO=getchar()));
    return f?-s:s;
}
 
const int N=1e5+10;
const int R=1e5;
 
int n;
struct Node{
    int h,k;
    bool operator < (const Node __) const {
        return h<__.h;
    }
} A[N];
 
 
int s[N<<2],t[N<<2];
void Down(int p) {
    if(!t[p]) return;
    t[p<<1]+=t[p],t[p<<1|1]+=t[p];
    s[p<<1]+=t[p],s[p<<1|1]+=t[p];
    t[p]=0;
}
 
void Upd(int p,int l,int r,int ql,int qr,int x){ 
    if(ql>qr) return;
    if(ql==l&&qr==r) {
        t[p]+=x;
        s[p]+=x;
        return;
    }
    Down(p);
    int mid=(l+r)>>1;
    if(qr<=mid) Upd(p<<1,l,mid,ql,qr,x);
    else if(ql>mid) Upd(p<<1|1,mid+1,r,ql,qr,x);
    else Upd(p<<1,l,mid,ql,mid,x),Upd(p<<1|1,mid+1,r,mid+1,qr,x);
    s[p]=max(s[p<<1],s[p<<1|1]);
}
 
int Que1(int p,int l,int r,int x) {
    do {
        int mid=(l+r)>>1;
        Down(p);
        x<=mid?(p=p<<1,r=mid):(p=p<<1|1,l=mid+1);
    } while(l!=r);
    return s[p];
}
 
int Que2(int p,int l,int r,int x) {
    do {
        int mid=(l+r)>>1;
        Down(p);
        if(s[p<<1|1]>x) p=p<<1|1,l=mid+1;
        else p=p<<1,r=mid;
    } while(l!=r);
    return s[p]<=x?1:l+1;
}
 
 
int main(){
    rep(i,1,n=rd()) A[i].h=rd(),A[i].k=rd();
    sort(A+1,A+n+1);
    rep(i,1,n) {
        int x=Que1(1,1,R,A[i].h-A[i].k+1);
        int l=Que2(1,1,R,x-1),r=Que2(1,1,R,x);
        Upd(1,1,R,l,A[i].h,1);
        Upd(1,1,R,r,r+A[i].k-max(0,(A[i].h-l+1))-1,1);
    }
    ll ans=0;
    rep(i,1,R) {
        int x=Que1(1,1,R,i);
        ans+=1ll*x*(x-1)/2;
    }
    printf("%lld\n",ans);
}
原文地址:https://www.cnblogs.com/chasedeath/p/11824984.html