【CF833E】Caramel Clouds(線段樹)

【CF833E】Caramel Clouds(線段樹)

題面

CF
洛谷ios

題解

首先把區間一段一段分出來,那麼只有四種狀況。
要麼沒有被任何一朵雲被覆蓋,那麼直接就會產生這一段的貢獻。
要麼被一朵雲覆蓋,要麼被兩朵雲覆蓋。
要麼被三朵及以上的雲所覆蓋,那麼這段的貢獻永遠取不到。spa

對於每朵雲預處理出只被其覆蓋的區間長度\(len[i]\),這樣子就能處理只選擇一朵雲的貢獻了。
如今考慮如何處理選擇兩朵雲。
這裏有兩種狀況。
第一種是兩朵雲無交,那麼貢獻就是\(len[i]+len[j]\)
不然的話有交,而且交的部分只被這兩朵雲所覆蓋,不能發現這樣子的狀況不會超過\(n\)個,這個東西能夠拿出來暴力更新。
這樣子咱們能夠預處理一個前綴的值,表明在這個位置以前選擇雲可以獲得的最大空出來的時間。code

對於第一種狀況,能夠按照價格大小構建一棵線段樹,這樣子每次就是區間查最大值。
對於第二種狀況,找到這個區間而後把兩個的貢獻算在一塊兒就行了。get

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<set>
#include<map>
using namespace std;
#define MAX 300300
inline int read()
{
    int x=0;bool t=false;char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=true,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return t?-x:x;
}
struct Cloud{int l,r,c;}c[MAX];
bool operator<(Cloud a,Cloud b){return a.c<b.c;}
struct Node{int t,opt,id;}a[MAX<<1];
bool operator<(Node a,Node b){return a.t<b.t;}
struct Qry{int k,id;}q[MAX];
bool operator<(Qry a,Qry b){return a.k<b.k;}
int n,m,C,cnt,ans[MAX],len[MAX],cho[MAX];
namespace SegmentTree
{
#define lson (now<<1)
#define rson (now<<1|1)
    int t[MAX<<2];
    void Modify(int now,int l,int r,int p,int w)
    {
        if(l==r){t[now]=w;return;}
        int mid=(l+r)>>1;
        if(p<=mid)Modify(lson,l,mid,p,w);
        else Modify(rson,mid+1,r,p,w);
        t[now]=max(t[lson],t[rson]);
    }
    int Getmax(int now,int l,int r)
    {
        if(l==r)return l;
        int mid=(l+r)>>1;
        if(t[lson]>t[rson])return Getmax(lson,l,mid);
        else return Getmax(rson,mid+1,r);
    }
    int Query(int now,int l,int r,int L,int R)
    {
        if(L<=l&&r<=R)return Getmax(now,l,r);
        int mid=(l+r)>>1,ret=0;
        if(L<=mid)ret=Query(lson,l,mid,L,R);
        if(R>mid)
        {
            int x=Query(rson,mid+1,r,L,R);
            if(len[x]>len[ret])ret=x;
        }
        return ret;
    }
}
using namespace SegmentTree;
set<int> S;
map<int,int> M[MAX];
int Calc(int i,int j){if(i>j)swap(i,j);return len[i]+len[j]+M[i][j];}
int main()
{
    n=read();C=read();
    for(int i=1;i<=n;++i)c[i].l=read(),c[i].r=read(),c[i].c=read();
    sort(&c[1],&c[n+1]);c[n+1]=(Cloud){0,0,2000000000};
    for(int i=1;i<=n;++i)a[++cnt]=(Node){c[i].l,1,i},a[++cnt]=(Node){c[i].r,-1,i};
    sort(&a[1],&a[cnt+1]);a[++cnt]=(Node){2000000010,1,n+1};
    m=read();for(int i=1;i<=m;++i)q[i].k=read(),q[i].id=i;
    sort(&q[1],&q[m+1]);
    int Sum=0,Del=0;
    for(int i=1,tim=0,pos=1;i<=cnt;++i)
    {
        int l=a[i].t-tim;tim=a[i].t;
        if(!S.size())Sum+=l;
        else if(S.size()==1)
        {
            int x=*S.begin();
            len[x]+=l;cho[x]+=l;Modify(1,1,n,x,len[x]);
            if(c[x].c<=C)
            {
                int l=1,r=upper_bound(&c[1],&c[n+1],(Cloud){0,0,C-c[x].c})-c-1,val=len[x];
                if(l<=x&&x<=r)
                {
                    if(l<=x-1)val=max(val,Calc(x,Query(1,1,n,l,x-1)));
                    if(x+1<=r)val=max(val,Calc(x,Query(1,1,n,x+1,r)));
                }
                else if(l<=r)val=max(val,Calc(x,Query(1,1,n,l,r)));
                cho[x]=max(cho[x],val);
                Del=max(Del,cho[x]);
            }
        }
        else if(S.size()==2)
        {
            int x=*S.begin(),y=*S.rbegin();M[x][y]+=l;
            if(c[x].c+c[y].c<=C)
            {
                cho[x]=max(cho[x],Calc(x,y));
                cho[y]=max(cho[y],Calc(x,y));
                Del=max(Del,max(cho[x],cho[y]));
            }
        }
        while(pos<=m&&Del+Sum>=q[pos].k)ans[q[pos].id]=tim-(Del+Sum-q[pos].k),++pos;
        if(a[i].opt==1)S.insert(a[i].id);
        else S.erase(a[i].id);
    }
    for(int i=1;i<=m;++i)printf("%d\n",ans[i]);
    return 0;
}
相關文章
相關標籤/搜索