zoukankan      html  css  js  c++  java
  • [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);
    }
    
  • 相关阅读:
    【计蒜客习题】取石子游戏
    【SCOI2005】骑士精神
    依赖背包
    强连通分量
    2017 Multi-University Training Contest
    2017 Multi-University Training Contest
    3月每日。
    2月每日DONE。
    寒假划水。
    基础实验2-2.5 整数分解为若干项之和 (20分)--dfs
  • 原文地址:https://www.cnblogs.com/chasedeath/p/11824984.html
Copyright © 2011-2022 走看看