bzoj5259: [Cerc2017]区间

还是很强的一个题 ORZ肉丝哥哥

对于两个相交区间,假如他们两个都是可行的,那么他们的交也可行,不然没可能两边都把它缺的补上

那么对于答案区间,向右找到第一个可行区间右端点覆盖询问区间,就是最优的

考虑扫描线,枚举右端点,对于当前还没有找到答案的询问,取左端点最大的去找答案

问题在于怎么快速判断一个区间是否可行

用max-min==R-L没有前途像我一样,要考虑其他性质

令i,i+1属于区间则对区间贡献1,假如[l,r]可行,那么它的权值就是r-l

那么开一棵线段树,表示每个位置到R的最大对数和+l,假如等于r说明是合法方案,求一下区间最大值和它的位置即可

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>

#define lc (now<<1)
#define rc (now<<1|1)
#define mid (ql+qr)/2
#define mx first
#define pos second
using namespace std;
typedef pair<int,int> pp;
const int _=1e2;
const int maxn=1e5+_;
const int fbin=(1<<17)+_;

struct trnode{pp p;int la;}tr[2*fbin];
void update(int now){tr[now].p=max(tr[lc].p,tr[rc].p);}
void pushdown(int now)
{
    if(tr[now].la!=0)
    {
        tr[lc].p.mx+=tr[now].la;tr[lc].la+=tr[now].la;
        tr[rc].p.mx+=tr[now].la;tr[rc].la+=tr[now].la;
        tr[now].la=0;
    }
}
void bt(int now,int ql,int qr)
{
    tr[now].p.mx=qr;tr[now].p.pos=qr;
    if(ql!=qr)
    {
        bt(lc,ql,mid);
        bt(rc,mid+1,qr);
    }
}
void add(int now,int ql,int qr,int l,int r,int w)
{
    if(ql==l&&qr==r){tr[now].p.mx++,tr[now].la++;return ;}
    pushdown(now);
         if(r<=mid)  add(lc,ql,mid,l,r,w);
    else if(mid+1<=l)add(rc,mid+1,qr,l,r,w);
    else add(lc,ql,mid,l,mid,w),add(rc,mid+1,qr,mid+1,r,w);
    update(now);
}
pp findmax(int now,int ql,int qr,int l,int r)
{
    if(ql==l&&qr==r)return tr[now].p;
    pushdown(now);
         if(r<=mid)  return findmax(lc,ql,mid,l,r);
    else if(mid+1<=l)return findmax(rc,mid+1,qr,l,r);
    else return max(findmax(lc,ql,mid,l,mid),findmax(rc,mid+1,qr,mid+1,r));
}

int n,a[maxn],b[maxn];
struct query{int l,r,id;}q[maxn];int Q; pp as[maxn];
bool cmp(query q1,query q2){return q1.r<q2.r;}
struct cmq{bool operator()(query q1,query q2){return q1.l<q2.l;}};
priority_queue<query,vector<query>,cmq>p;
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]),b[a[i]]=i;
    
    scanf("%d",&Q);
    for(int i=1;i<=Q;i++)
        scanf("%d%d",&q[i].l,&q[i].r),q[i].id=i;
    sort(q+1,q+Q+1,cmp);
    
    int tp=1; bt(1,1,n);
    int x;query tq;pp tt;
    for(int i=1;i<=n;i++)
    {
        if(a[i]!=1)
        {
            x=b[a[i]-1];
            if(x<i)add(1,1,n,1,x,i);
        }
        if(a[i]!=n)
        {
            x=b[a[i]+1];
            if(x<i)add(1,1,n,1,x,i);
        }
        
        while(tp<=n&&q[tp].r==i)p.push(q[tp]),tp++;
        while(!p.empty())
        {
            tq=p.top();
            tt=findmax(1,1,n,1,tq.l);
            if(tt.first==i)
            {
                as[tq.id]=make_pair(tt.pos,i);
                p.pop();
            }
            else break;
        }
    }
    
    for(int i=1;i<=Q;i++)printf("%d %d\n",as[i].mx,as[i].pos);
    
    return 0;
}

 

posted @ 2019-03-29 15:06  AKCqhzdy  阅读(280)  评论(0编辑  收藏  举报