[Codeforces276E]Sign on Fence CDQ分治

这题可以用可持久化线段树做,用那种方法可以强制在线
考场里觉得分治好写就直接上了

将篱笆从大到小排序,记录每一个篱笆的位置
solve(l,r,S)对[l,r]区间以及询问集合S进行分治
将1到mid篱笆的线段树上所在位置变成1,对所有的询问集合查询[l,r]区间内最长的连续1的数量是否大于等于w,若成立则将该询问放在左半区间的询问集合里,否则扔到另外一个区间的询问集合里面

分治一个log,线段树一个log,最后的复杂度是 O(nlog2n)

#include 

#define mid ((l+r)>>1)
#define ls l,mid,t<<1
#define rs mid+1,r,t<<1^1

#define N 100050
using namespace std;

struct Afrojack{ int h,_; }A[N];
bool operator <(Afrojack p1, Afrojack p2) { return p1.h > p2.h; }
struct Monster{ int l,r,w,ans; }Q[N];

int n,m,e[N],tmp[N],T;

int ll,rr,v,x;

struct Node{
    int al,ar,siz,ans;
}tr[4*N],ret,id;

Node operator +(Node p1, Node p2) {
    Node ret;
    ret.siz = p1.siz + p2.siz;

    ret.ans = max( p1.ans, p2.ans );
    ret.ans = max( ret.ans, p1.ar + p2.al );

    ret.ar = p2.ar;
    p2.ar == p2.siz ? ret.ar += p1.ar :0;

    ret.al = p1.al;
    p1.al == p1.siz ? ret.al += p2.al :0;
    return ret;
}

inline int rd() {
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}

void init() {
    n = rd();
    for (int _=1;_<=n;_++) A[_].h = rd(), A[_]._ = _;
    m = rd();
    for (int _=1;_<=m;_++)
        Q[_].l = rd(), Q[_].r = rd(), Q[_].w = rd();
    sort(A+1,A+n+1);
    for (int _=1;_<=m;_++) e[_] = _;
}

Node build(int l,int r,int t) {
    return tr[t] = l==r ? (Node){0,0,1,0} : build(ls) + build(rs);
}

void update(int l,int r,int t) {
    if (l == r)
        return tr[t] = v ? (Node){1,1,1,1} : (Node){0,0,1,0}, (void)0;
    x <= mid ? update(ls) : update(rs);
    tr[t] = tr[t<<1] + tr[t<<1^1];
}

void query(int l,int r,int t) {
    if (l >= ll && r <= rr) return ret = ret + tr[t], (void)0;
    if (ll <= mid) query(ls);
    if (rr > mid) query(rs);
}

void solve(int l,int r,int ql,int qr) {
    if (ql > qr) return ;
    if (l == r) {
        for (int _=ql;_<=qr;_++) Q[ e[_] ].ans = A[l].h;
        return ;
    }

    while (T1]._, v = 1, update(1,n,1), T++;
    while (T>mid)
        x = A[T]._, v = 0, update(1,n,1), T--;

    int L = ql-1, R = qr+1;
    for (int _=ql;_<=qr;_++) {
        ll = Q[ e[_] ].l , rr = Q[ e[_] ].r, ret = id;
        query(1,n,1);
        ret.ans >= Q[ e[_] ].w ? tmp[++L] = e[_] : tmp[ --R ] = e[_];
    }
    for (int _=ql;_<=qr;_++) e[_] = tmp[_];

    solve(l,mid,ql,L);
    solve(mid+1,r,R,qr);
}

int main() {
    init();
    build(1,n,1);
    solve(1,n,1,m);
    for (int _=1;_<=m;_++) printf("%d\n",Q[_].ans);
    return 0;
} 

你可能感兴趣的:(CDQ分治)