51nod1287(二分、线段树)

链接:https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1287

思路:二分查找大于等于b[i]的最前面的位置(想起一次错漏百出的网赛中一道没在比赛A掉的题),并更新线段树,总复杂度nlogn。

我并不是停留在舒适区,而是找回当年因为死套模板而没有去深刻理解的东西,下次再接触到这些东西的时候只能称呼你们学长学姐了。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 5e4 + 3;
struct node
{
    int l,r;
    int val;
}q[N<<2];
int a[N],b[N];
void built(int l,int r,int pos)
{
    q[pos].l = l;
    q[pos].r = r;
    if(l == r)
    {
        q[pos].val = a[l];
        return;
    }
    int mid = (l + r) >> 1;
    built(l,mid,2*pos);
    built(mid+1,r,2*pos+1);
    q[pos].val= max(q[2*pos].val,q[2*pos+1].val);
}
void update(int i,int pos)
{
    if(q[pos].l == q[pos].r)
    {
        q[pos].val++;
        return;
    }
    int mid = (q[pos].l + q[pos].r) >> 1;
    if(i > mid)
        update(i,2*pos+1);
    else
        update(i,2*pos);
    q[pos].val= max(q[2*pos].val,q[2*pos+1].val);
}
int get_id(int val,int pos)
{
    if(q[pos].l == q[pos].r)
    {
        if(val > q[pos].val)
            return 0;
        return q[pos].l;
    }
    if(val > q[2*pos].val)
        return get_id(val,2*pos+1);
    else
        return get_id(val,2*pos);
}
int main()
{
    int m,n;
    scanf("%d %d",&m,&n);
    for(int i = 1; i <= m; i++)
        scanf("%d",&a[i]);
    for(int i = 1; i <= n; i++)
        scanf("%d",&b[i]);
    built(1,m,1);
    for(int i = 1; i <= n; i++)
    {
        int id = get_id(b[i],1);
        if(id > 1)
        {
            a[id-1]++;
            update(id-1,1);
        }
    }
    for(int i = 1; i <= m; i++)
        printf("%d\n",a[i]);
    return 0;
}
时间: 2024-07-29 09:04:40

51nod1287(二分、线段树)的相关文章

51nod1287(二分/线段树区间最值&amp;单点更新)

题目链接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1287 题意:中文题诶- 解法1:b[i] 存储 max(a[0], ....., a[i]),显然 b 是单调不减的,所以直接二分 x,再更新 a 和 b 数组即可: 代码: 1 #include <iostream> 2 #include <stdio.h> 3 using namespace std; 4 5 const int MAXN =

【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

HDU5008 Boring String Problem(后缀数组 + 二分 + 线段树)

题目 Source http://acm.hdu.edu.cn/showproblem.php?pid=5008 Description In this problem, you are given a string s and q queries. For each query, you should answer that when all distinct substrings of string s were sorted lexicographically, which one is

(困难) 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. Afte

zoj 3888 Twelves Monkeys 二分+线段树维护次小值

链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3888 Twelves Monkeys Time Limit: 5 Seconds      Memory Limit: 32768 KB James Cole is a convicted criminal living beneath a post-apocalyptic Philadelphia. Many years ago, the Earth's surf

bzoj1568: [JSOI2008]Blue Mary开公司 三分+二分+线段树

答案序列一定是个下凸壳,因此添加的等差数列与其之差是个单峰函数,可以先三分求出最值,再二分求出零点,然后用线段树,将得到的区间修改为一个等差数列. 这个做法应该比较好想吧,虽然比较慢…… #include<cstdio> #define Z int l=1,int r=N,int k=1 #define N 50000 #define M (l+r>>1) #define P (k<<1) #define S (k<<1|1) #define K l,r,k

计蒜客16492 building(二分线段树/分块)

题解: 考虑用线段树维护楼的最大值,然后这个问题就很简单了. 每次可以向左二分出比x高的第一个楼a,同理也可以向右二分出另一个楼b,如果a,b都存在,答案就是b-a-1. 注意到二分是可以直接在线段树上进行的,所以复杂度是O(nlogn). 当然这里是用分块做的,更暴力一些. #include <iostream> #include <cstdio> #include <cstring> #include <cmath> using namespace st

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

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

poj1201(二分+线段树)或(差分约束系统)

题意:数轴上每个位置为0或是1,给n(1 <= n <= 50000)个区间[ai, bi],每个区间内至少有 ci 个1.0 <= ai <= bi <= 50000,1 <= ci <= bi - ai+1.问数轴上至少有多少个1可以满足要求. 解法1:现将区间按右端点排序,然后每个区间内的点尽量往右边放,这样子可以照顾到以后的.在找每个区间的放法时,线段树查询区间1的个数,二分查找要放的后缀位置,然后将整个区间后缀全部涂上1.总复杂度是nlognlogn.网

hdu6070(分数规划/二分+线段树区间更新,区间最值)

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=6070 题意: 给出一个题目提交序列, 从中选出一个正确率最小的子串. 选中的子串中每个题目当且仅当最后一次提交是正确的. 思路: 分数规划 二分答案, 然后在 check 函数中查找是否存在某个区j间 [l, r] 使得 sum(l, r) / (r - l + 1) <= mid, 即 sum(l, r) + l * mid <= (r + 1) * mid. 可以用个线段树来维护 sum(l