(困难) CF 484E Sign on Fence,整体二分+线段树

Bizon the Champion has recently finished painting his wood fence. The fence consists of a sequence of n panels of 1 meter width and of arbitrary height. The i-th panel‘s height is hi meters. The adjacent planks follow without a gap between them.

After Bizon painted the fence he decided to put a "for sale" sign on it. The sign will be drawn on a rectangular piece of paper and placed on the fence so that the sides of the sign are parallel to the fence panels and are also aligned with the edges of some panels. Bizon the Champion introduced the following constraints for the sign position:

  1. The width of the sign should be exactly w meters.
  2. The sign must fit into the segment of the fence from the l-th to the r-th panels, inclusive (also, it can‘t exceed the fence‘s bound in vertical direction).

The sign will be really pretty, So Bizon the Champion wants the sign‘s height to be as large as possible.

You are given the description of the fence and several queries for placing sign. For each query print the maximum possible height of the sign that can be placed on the corresponding segment of the fence with the given fixed width of the sign.

  纪念人生第一道Div 1的E题,终于搞定了。

  题目就是N个值的M次询问,然后对于一个询问来说就是二分答案。对于M次询问的话,想到了整体二分。然后数据结构的话就是区间合并的线段树,比较经典的问题。

  代码如下:

// ━━━━━━神兽出没━━━━━━
//      ┏┓       ┏┓
//     ┏┛┻━━━━━━━┛┻┓
//     ┃           ┃
//     ┃     ━     ┃
//     ████━████   ┃
//     ┃           ┃
//     ┃    ┻      ┃
//     ┃           ┃
//     ┗━┓       ┏━┛
//       ┃       ┃
//       ┃       ┃
//       ┃       ┗━━━┓
//       ┃           ┣┓
//       ┃           ┏┛
//       ┗┓┓┏━━━━━┳┓┏┛
//        ┃┫┫     ┃┫┫
//        ┗┻┛     ┗┻┛
//
// ━━━━━━感觉萌萌哒━━━━━━

// Author        : WhyWhy
// Created Time  : 2016年01月22日 星期五 17时06分36秒
// File Name     : L_1.cpp

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <math.h>
#include <stdlib.h>
#include <time.h>

using namespace std;

const int MaxN=100005<<1;

struct OPE { int l,r,w,id; } ope[MaxN],to1[MaxN],to2[MaxN];

int N,M;
int ans[MaxN];

///////////////////////////////

#define lc (po<<1)
#define rc ((po<<1)|1)
#define lson L,M,lc
#define rson M+1,R,rc

struct ANS {
    int num,lnum,rnum;
    ANS(int a=0,int b=0,int c=0):num(a),lnum(b),rnum(c) {}
};

ANS BIT[MaxN<<2];

ANS merge(int len1,int len2,ANS a1,ANS a2) {
    ANS ret;
    ret.num=max(max(a1.rnum+a2.lnum,a1.num),a2.num);
    ret.lnum=(len1==a1.num) ? len1+a2.lnum : a1.lnum;
    ret.rnum=(len2==a2.num) ? len2+a1.rnum : a2.rnum;
    return ret;
}

inline void pushUP(int len1,int len2,int po) {
    BIT[po]=merge(len1,len2,BIT[lc],BIT[rc]);
}

void update(int up,int ut,int L,int R,int po) {
    if(L==R) {
        BIT[po].num=BIT[po].lnum=BIT[po].rnum=ut;
        return;
    }

    int M=(L+R)>>1;
    if(up<=M) update(up,ut,lson);
    else update(up,ut,rson);

    pushUP(M-L+1,R-M,po);
}

ANS query(int ql,int qr,int L,int R,int po) {
    if(ql<=L && qr>=R) return BIT[po];

    int M=(L+R)>>1;
    if(ql>M) return query(ql,qr,rson);
    if(qr<=M) return query(ql,qr,lson);

    return merge(M-ql+1,qr-M,query(ql,M,lson),query(M+1,qr,rson));        // !!!
}

///////////////////////////////

int tmp[MaxN];

void getans(int ql,int qr,int L,int R) {
    if(ql>qr) return;
    if(L==R) {
        for(int i=ql;i<=qr;++i) ans[ope[i].id]=L;
        return;
    }

    int M=(L+R+1)>>1;
    for(int i=ql;i<=qr;++i)
        if(!ope[i].id && ope[i].w>=M)
            update(ope[i].l,1,1,N,1),tmp[i]=2;
        else if(ope[i].id && ope[i].w<=query(ope[i].l,ope[i].r,1,N,1).num)
            tmp[i]=1;
        else tmp[i]=0;

    int cou1=0,cou2=0;
    for(int i=ql;i<=qr;++i)
        if(tmp[i]) {
            to2[cou2++]=ope[i];
            if(tmp[i]==2) update(ope[i].l,0,1,N,1);
        }
        else to1[cou1++]=ope[i];

    int t=ql;
    for(int i=0;i<cou1;++i) ope[t++]=to1[i];
    for(int i=0;i<cou2;++i) ope[t++]=to2[i];

    getans(ql+cou1,qr,M,R);            // !!! 大的那些要被用到,在小的里面。

    for(int i=ql+cou1;i<=qr;++i)
        if(!ope[i].id)
            update(ope[i].l,1,1,N,1);

    getans(ql,ql+cou1-1,L,M-1);
}

///////////////////////////////

int main() {
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);

    int t,cou=0;
    scanf("%d",&N);
    for(int i=1;i<=N;++i) {
        scanf("%d",&t);
        ope[++cou].w=t;
        ope[cou].l=i;
        ope[cou].id=0;
    }
    scanf("%d",&M);
    for(int i=1;i<=M;++i) {
        ope[++cou].id=i;
        scanf("%d %d %d",&ope[cou].l,&ope[cou].r,&ope[cou].w);
    }
    getans(1,cou,1,1000000000);
    for(int i=1;i<=M;++i) printf("%d\n",ans[i]);

    return 0;
}

时间: 2024-10-10 20:17:47

(困难) CF 484E Sign on Fence,整体二分+线段树的相关文章

Codeforces 484E Sign on Fence(可持久化线段树+二分)

题目链接:Codeforces 484E Sign on Fence 题目大意:给定给一个序列,每个位置有一个值,表示高度,现在有若干查询,每次查询l,r,w,表示在区间l,r中, 连续最长长度大于w的最大高度为多少. 解题思路:可持久化线段树维护区间合并,前端时间碰到一题可持久化字典树,就去查了一下相关论文,大概知道了是 什么东西. 将高度按照从大到小的顺序排序,然后每次插入一个位置,线段树维护最长连续区间,因为插入是按照从大到小的顺 序,所以每次的线段树中的连续最大长度都是满足高度大于等于当

Codeforces 484E. Sign on Fence 可持久化线段树

大概题意: 给一数组a,问在某一区间L~R中,问对于连续的长为W的一段中最小的数字的最大值是多少. 显然可以转化成二分高度然后判断可行性的问题. 考虑到高度肯定为数组中的某一个值,将数组从大到小排序. 建n棵线段树,对于第 i 棵线段树,将 大于等于a[i] 的叶子的值设置为1,其他的叶子设置为0,问题就转化成了用线段树求某一区间中最长的连续的1的个数,这是一个线段树的经典问题,可以通过维护每个节点的 左边连续和,右边连续和,连续和的最大值 得到. 由于空间问题,不可能建立10^5棵线段树,考虑

【BZOJ-3110】K大数查询 整体二分 + 线段树

3110: [Zjoi2013]K大数查询 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 6265  Solved: 2060[Submit][Status][Discuss] Description 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是多少. Input 第一行N,M接下来M行,每行形如1 a

BZOJ 2527 Poi2011 Meteors 整体二分+线段树 / 可持久化线段树(MLE)

题目大意:给定一个环,每个节点有一个所属国家,k次事件,每次对[l,r]区间上的每个点点权加上一个值,求每个国家最早多少次操作之后所有点的点权和能达到一个值 首先我们考虑暴力想法 对于每个国家分开讨论 二分操作次数 但是这样每次Judge的时候我们要模拟1~mid所有的操作 浪费在这里的复杂度实在太大 这样做每个国家需要模拟O(klogk)次操作 时间复杂度O(nklogk) TLE 我们需要对浪费在这里的复杂度做一些改进 1.可持久化线段树(MLE) 每次二分一个mid之后 我们要找到mid次

【LUOGU???】WD与地图 整体二分 线段树合并

题目大意 有一个简单有向图.每个点有点权. 有三种操作: 修改点权 删除一条边 询问和某个点在同一个强连通分量中的点的前 \(k\) 大点权和. \(n\leq 100000,m,q\leq 200000\) 题解 把操作反过来,每次只有加边操作. 用线段树维护同一个强连通分量内的点的点权. 用整体二分去计算每条边的两个端点被合并的时间. 每次把加入时间 \(\leq tmid\) 的边拿出来跑一次 tarjan,就可以知道哪些边在 \(\leq tmid\) 的时间内被缩掉了. 用带撤回的并查

Codeforces 484E Sign on Fence(是持久的段树+二分法)

题目链接:Codeforces 484E Sign on Fence 题目大意:给定给一个序列,每一个位置有一个值,表示高度,如今有若干查询,每次查询l,r,w,表示在区间l,r中, 连续最长长度大于w的最大高度为多少. 解题思路:可持久化线段树维护区间合并,前端时间碰到一题可持久化字典树,就去查了一下相关论文,大概知道了是 什么东西. 将高度依照从大到小的顺序排序,然后每次插入一个位置,线段树维护最长连续区间,由于插入是依照从大到小的顺 序,所以每次的线段树中的连续最大长度都是满足高度大于等于

【BZOJ4009】[HNOI2015]接水果 DFS序+整体二分+扫描线+树状数组

[BZOJ4009][HNOI2015]接水果 Description 风见幽香非常喜欢玩一个叫做 osu!的游戏,其中她最喜欢玩的模式就是接水果.由于她已经DT FC 了The big black,  她觉得这个游戏太简单了,于是发明了一个更加难的版本.首先有一个地图,是一棵由 n 个顶点.n-1 条边组成的树(例如图 1给出的树包含 8 个顶点.7 条边).这颗树上有 P 个盘子,每个盘子实际上是一条路径(例如图 1 中顶点 6 到顶点 8 的路径),并且每个盘子还有一个权值.第 i 个盘子

CF E. Till I Collapse 整体二分+根号分治

本来模拟赛想出这个来的,但是感觉不太友好啊~ 主席树可以直接屎过去,但是空间消耗很大. 考虑用整体二分: code: #include <bits/stdc++.h> #define N 100003 #define ll long long #define setIO(s) freopen(s".in","r",stdin) using namespace std; int A[N],C[N],ans[N],n; int solve(int x) {

CodeForces 484E Sign on Fence

题意: n(10^5)个模板形成的栅栏  q(10^5)个询问  每个询问要求在[u,v]木板区间内摆放一个宽度为w的矩形  问矩形最大的高是多少 思路: 对于每个询问  可以通过logn的二分来将求解最大h的问题转化为当前h'情况下的判定问题 为什么可以二分呢  因为如果我们将木板排序  从大到小的依次放置它们的位置上  那么对于某一时刻  线段上连续的1就代表了矩形的宽  同时这时的h最小为二分到的木板高度h'  明显h'和这时矩形的宽满足单调性 得到了h'后只需要快速的找出[u,v]区间连