【JOISC2012】fish

Description

  有 \(n\) 條魚,第 \(i\) 條魚的長度爲 \(L_i\),顏色是 \(C_i\)\(C_i\) 只能是 'R','G','B')。
  你須要從中挑出至少一條魚,要求挑出的魚中不能存在兩條魚 \(x,y\) 知足 \(2L_x\le L_y\)
  求能夠挑出 \(a\) 條紅魚、\(b\) 條綠魚、\(c\) 條藍魚的三元組 \((a,b,c)\) 的個數。
  \(n\le 5\times 10^5\)node

Solution

  將全部魚按 \(L\) 從小到大排序。
  枚舉每條魚 \(l\)\(L\) 最小的魚,求在此基礎上能挑出的 \(L\) 最大的魚 \(r\)。設第 \([l,r]\) 條魚中有 \(a\) 條紅魚,\(b\) 條綠魚,\(c\) 條藍魚,則 \((0,0,0)\)\((a,b,c)\) 這個立方體空間中的全部三維點都是能夠選的。問題轉化成了求 \(n\) 個立方體的體積並。
  \(n\) 個立方體的前左下端點都是 \((0,0,0)\),這個性質很好,咱們能夠用掃描線倒序掃第一維,第2、三維組成的平面 必定是一個包含左下角的凸包。不難發現咱們要支持快速將一個前綴對一個參數取 max,以及總體求和,直接線段樹就完了。時間 \(O(n\log n)\)c++

  固然也能夠維護一個 set 記錄第2、三維組成的平面上的凸包的每一個頂點,區間更新 max 時暴力刪掉中間全部被覆蓋掉的頂點便可。spa

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
inline int rd(){
    char c=getchar();int x=0,flag=1;
    for(;c<'0'||c>'9';c=getchar())if(c=='-')flag=-1;
    for(;c>='0'&&c<='9';c=getchar())x=x*10+c-'0';
    return x*flag;
}
struct fish{
    int l,c;
    friend inline bool operator < (fish a,fish b){
        return a.l>b.l;
    }
}a[500010];
struct node{
    int x,y,z;
    friend inline bool operator < (node a,node b){
        return a.x>b.x;
    }
}p[500010];
struct seg_tree{
    ll sum;int tag,mx,mn;
}st[2000010]={0};
int n,sz[3]={0};
inline void pushdown(int s,int l,int r){
    if(!st[s].tag) return;
    int mid=(l+r)>>1,v=st[s].tag;
    st[s<<1].tag=st[s<<1].mx=st[s<<1].mn=v;
    st[s<<1].sum=(ll)v*(mid-l+1);
    st[s<<1|1].tag=st[s<<1|1].mx=st[s<<1|1].mn=v;
    st[s<<1|1].sum=(ll)v*(r-mid);
    return (void)(st[s].tag=0);
}
inline void pushup(int s){
    st[s].sum=st[s<<1].sum+st[s<<1|1].sum;
    st[s].mx=max(st[s<<1].mx,st[s<<1|1].mx);
    st[s].mn=min(st[s<<1].mn,st[s<<1|1].mn);
    return;
}
inline void upd(int s,int l,int r,int x,int y,int v){
    if(st[s].mn>=v) return;
    if(x<=l&&r<=y&&st[s].mx<=v){
        st[s].tag=st[s].mx=st[s].mn=v;
        st[s].sum=(ll)v*(r-l+1);
        return;
    }
    int mid=(l+r)>>1;pushdown(s,l,r);
    if(x<=mid) upd(s<<1,l,mid,x,y,v);
    if(mid<y) upd(s<<1|1,mid+1,r,x,y,v);
    return pushup(s);
}
int main(){
    n=rd();
    for(int i=1;i<=n;i++){
        int l=rd();char c[2];scanf("%s",c);
        a[i]=(fish){l,(c[0]=='R')?0:(c[0]=='G')?1:2};
    }
    sort(a+1,a+n+1);
    for(int i=1,j=1;i<=n;i++){
        for(;j<=n&&(a[j].l<<1)>a[i].l;j++)
            sz[a[j].c]++;
        p[i]=(node){sz[0]+1,sz[1]+1,sz[2]+1};
        sz[a[i].c]--;
    }
    sort(p+1,p+n+1);
    ll ans=0;
    for(int i=n+1,j=1;i;i--){
        for(;j<=n&&p[j].x==i;j++)
            upd(1,1,n+1,1,p[j].y,p[j].z);
        ans+=st[1].sum;
    }
    return printf("%lld\n",ans-1),0;
}
相關文章
相關標籤/搜索