【Codeforces 484E】Sign on Fence | 二分、主席树维护线段合并

题目链接:https://codeforces.com/contest/484/problem/E

题目大意:

给出一个序列,进行q次询问

每次查询区间[l,r]内,所有长度为w的区间最小值 的最大值

题目思路:

巨秀的一个思路

最小最大值问题,首先考虑二分当前答案

二分当前答案是否能作为一个长度大于等于w的区间的最小值

考虑如何check这个ans,假设把大于等于w的位置都设为1,那么就相当于每次check区间[l,r]内的最长连续1的长度是否大于等于w

如果大于等于w,那么这个ans,在区间[l,r]内可以作为最小值,继续扩大当前ans

否则,就要缩小这个ans

但是不可以对于每一个询问的w都建立一个线段树,之后在线段树上进行线段树合并

考虑最后的答案必然是数组中的某个值,所以可以对数组排序。

之后建立一个后缀的主席树,主席树维护位置的权值,那么就可以得出,大于等于当前值的,最长连续1的区间长度。

之后对这个进行二分就可以了

复杂度:O(nlog^2)

Code:

/*** keep hungry and calm CoolGuang!  ***/
#pragma GCC optimize("Ofast","unroll-loops","omit-frame-pointer","inline")
#pragma GCC optimize(3)
#include <bits/stdc++.h>
#include<stdio.h>
#include<queue>
#include<algorithm>
#include<string.h>
#include<iostream>
#define debug(x) cout<<#x<<":"<<x<<endl;
#define d(x) printf("%lld\n",x);
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
const ll INF= 1e18;
const ll maxn = 2e5+700;
const int mod= 998244353;
const int up = 1e9;
template<typename T>inline void read(T &a){char c=getchar();T x=0,f=1;while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();}a=f*x;}
ll n,m,p;
ll num[maxn];
struct node{
    int l,r,lc,rc,c;
}t[maxn*40];
int root[maxn*40];
int cnt = 0;
struct Query{
    int x,id;
    bool friend operator<(Query a,Query b){
        return a.x < b.x;
    }
}q[maxn];
void Insert(int &now,int pre,int l,int r,int pos){
   t[now = ++cnt] = t[pre];
   if(l == r){
        t[now].c = t[now].lc = t[now].rc = 1;
        return;
   }
   int mid = (l+r)/2;
   if(pos <= mid) Insert(t[now].l,t[pre].l,l,mid,pos);
   else Insert(t[now].r,t[pre].r,mid+1,r,pos);

   int ls = t[now].l,rs = t[now].r;

   if(t[ls].lc == mid-l+1) t[now].lc = t[ls].lc + t[rs].lc;
   else t[now].lc = t[ls].lc;
   if(t[rs].rc == r-mid) t[now].rc = t[rs].rc + t[ls].rc;
   else t[now].rc = t[rs].rc;

   t[now].c = max(t[now].lc,t[now].rc);
   t[now].c = max(t[now].c,t[ls].rc+t[rs].lc);
   t[now].c = max(t[now].c,t[rs].c);
   t[now].c = max(t[now].c,t[ls].c);
}
int last = 0,res = 0;
void Find(int now,int l,int r,int x,int y){
    if(x<=l && y>=r){
        res = max(res,t[now].c);
        res = max(res,t[now].lc+last);
        if(t[now].rc == r-l+1) last = last+t[now].rc;
        else last = t[now].rc;
        return ;
    }
    int mid = (l+r)/2;
    if(x<=mid) Find(t[now].l,l,mid,x,y);
    if(y>mid) Find(t[now].r,mid+1,r,x,y);
}
int main(){
    read(n);
    for(int i=1;i<=n;i++){
        read(q[i].x);
        q[i].id = i;
    }
    sort(q+1,q+1+n);
    for(int i=n;i>=1;i--) Insert(root[i],root[i+1],1,n,q[i].id);
    read(m);
    for(int i=1;i<=m;i++){
        int x,y,w;read(x);read(y);read(w);
        int l = 1,r = n;
        int ans = 0;

        while(l<=r){
            int mid = (l+r)/2;
            res = last = 0;
            Find(root[mid],1,n,x,y);
            if(res>=w){
                ans = mid;
                l = mid+1;
            }else r = mid-1;
        }
        printf("%d\n",q[ans].x);
    }
    return 0;
}
/***
***/

猜你喜欢

转载自blog.csdn.net/qq_43857314/article/details/111033376