2019杭电多校第三次hdu6609 Find the answer(线段树)

Find the answer

题目传送门

解题思路

要想变0的个数最少,显然是优先把大的变成0。所以离散化,建立一颗权值线段树,维护区间和与区间元素数量,假设至少减去k才能满足条件,查询大于等于k的最少数量即可。

代码如下

#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;

inline int read(){
    int res = 0, w = 0; char ch = 0;
    while(!isdigit(ch)){
        w |= ch == '-', ch = getchar();
    }
    while(isdigit(ch)){
        res = (res << 3) + (res << 1) + (ch ^ 48);
        ch = getchar();
    }
    return w ? -res : res;
}

const int N = 200005;

struct T{
    int l, r;
    int c;
    ll sum;
}tree[N<<2];
ll a[N], b[N];
void build(int k, int l, int r)
{
    tree[k].l = l, tree[k].r = r;
    tree[k].c = tree[k].sum = 0;
    if(tree[k].l == tree[k].r)
        return;
    int mid = (tree[k].l + tree[k].r) / 2;
    build(2*k, l, mid);
    build(2*k+1, mid + 1, r);
}

void insert(int k, int x)
{
    if(tree[k].l == tree[k].r){
        tree[k].c ++;
        tree[k].sum += b[x];
        return;
    }
    int mid = (tree[k].l + tree[k].r) / 2;
    if(x <= mid)
        insert(2*k, x);
    else
        insert(2*k+1, x);
    tree[k].c = tree[2*k].c + tree[2*k+1].c;
    tree[k].sum = tree[2*k].sum + tree[2*k+1].sum;
}

ll query(int k, ll x)
{
    if(tree[k].l == tree[k].r)
        return (x - 1) / b[tree[k].l] + 1;
    if(tree[2*k+1].sum > x)
        return query(2*k+1, x);
    else if(tree[2*k+1].sum < x){
        x -= tree[2*k+1].sum;
        return query(2*k, x) + tree[2*k+1].c;
    }
    else
        return tree[2*k+1].c;
}

int main()
{
    int q;
    scanf("%d", &q);
    while(q --){
        int n;
        ll m;
        scanf("%d%lld", &n, &m);
        for(int i = 1; i <= n; i ++){
            scanf("%lld", &a[i]);
            b[i] = a[i];
        }
        sort(b + 1, b + n + 1);
        int k = unique(b + 1, b + n + 1) - b - 1;
        build(1, 1, k);
        ll sum = 0;
        for(int i = 1; i <= n; i ++){
            sum += a[i];
            if(sum - m > 0)
                printf("%lld ", query(1, sum - m));
            else
                printf("0 ");
            int x = lower_bound(b + 1, b + k + 1, a[i]) - b;
            insert(1, x);
        }
        printf("\n");
    }
    return 0;
}

原文地址:https://www.cnblogs.com/whisperlzw/p/11272351.html

时间: 2024-08-01 19:54:25

2019杭电多校第三次hdu6609 Find the answer(线段树)的相关文章

2019 杭电多校 第三场

2019 Multi-University Training Contest 3 补题链接:2019 Multi-University Training Contest 3 1002 Blow up the city (HDU-6604) 题意 给定 \(n\) 个点和 \(m\) 条边的有向无环图,给出 \(q\) 次询问,每个询问给出 \(a\) 和 \(b\),求有多少个点,满足该点删去后 \(a\) 和 \(b\) 中至少一个点不能到达出度为 \(0\) 的点. 题解 支配树/灭绝树 拓

2019杭电多校第三场 1004 Distribution of books

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6606 考虑二分答案,我们二分一个值\(x\),那么要怎么来验证这个答案是否可行,考虑dp求解,设\(dp[i]\)为前i个在答案为\(x\)的情况下划分最最多组数,那么若\(dp[n] \geq k\) 则这个x可行, 很显然可以看出\(x\)是单调的,所以二分. \[dp[i] = max(dp[j]) + 1 (sum[i] - sum[j-1] \leq x)\] 如果直接采用暴力枚举的话复杂

2019杭电多校第三场 1008 K-th Closest Distance

题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=6621 考虑主席树,我们先将所有值离散化之后建主席树.对于每个查询\(s,t,p,k\) 我们考虑二分一个值\(mid\),考虑当前区间内,\([p-mid, p+mid]\)的值有多少个,很显然这是符合单调性的,那么我们只需要每次判断即可.时间复杂度\(O(nlog^2n)\) #include <bits/stdc++.h> #define pii pair<int, int> #d

2019杭电多校第九场

2019杭电多校第九场 熟悉的后半场挂机节奏,又苟进首页了,很快乐 1001. Rikka with Quicksort upsolved 不是我做的,1e9调和级数分段打表 1002. Rikka with Cake solved at 01:11 有一个矩形,给你很多射线(射线只有横平竖直的四个方向),问把矩形切成了多少块 队友说答案是交点数加一,作为一个合格的工具人,当然是把队友的想法实现啦 二维坐标离散化枚举纵坐标维护横坐标,常规套路,树状数组也可以做(我是线段树写习惯了根本没想起来还有

2019 杭电多校 第五场

2019 Multi-University Training Contest 5 补题链接:2019 Multi-University Training Contest 5 罚时爆炸 自闭场 1004 equation (HDU 6627) 题意: 给定一个整数 \(C\) 和 \(N\) 组 \(a_i,b_i\),求 \(∑_{i=1}^N|a_i\cdot x + b_i| = C\) 的所有解,如果有无穷多个解就输出 -1. 思路 分类讨论 分类讨论去绝对值.根据 \(b_i / a_i

2019年杭电多校第三场 1011题Squrirrel(HDU6613+树DP)

题目链接 传送门 题意 给你一棵无根树,要你寻找一个根节点使得在将一条边权变为\(0\)后,离树根最远的点到根节点的距离最小. 思路 本题和求树的直径很像,不过要记得的东西有点多,且状态也很多. \(fi[u][0]\)表示在\(u\)这个结点不删边沿着子树方向能到达的最远距离,\(se[u][0]\)为第二远,\(th[u][0]\)为第三远,\(fa[u][0]\)表示沿着父亲方向能到达的最远距离,第二维为\(1\)表示删一条边能到达的距离. 不删边的转移和求树的直径转移方程基本上是一样的,

2019 杭电多校 第九场

2019 Multi-University Training Contest 9 补题链接:2019 Multi-University Training Contest 9 1005 Rikka with Game (HDU 6684) 题意 Rikka 和 Yuta 玩游戏.给定一个字符串.两人轮流对字符串操作.可以选择结束游戏,也可以改变其中一个字符,改变规则是:\(a\rightarrow b,b\rightarrow c,-,y\rightarrow z,z\rightarrow a.\

2018 Multi-University Training Contest 3 杭电多校第三场

躺了几天 终于记得来填坑了 1001 Ascending Rating   (hdoj 6319) 链接:http://acm.hdu.edu.cn/showproblem.php?pid=6319 单调队列 具体有点类似双端队列滑动窗口 题意:在一个队列中 每次都给定一个固定长度的区间 从i=1开始向后移动 每次在这个区间中进行a[i]和a[j]的比较 若a[i]<a[j] count++ 最大值更新为a[j] ,每个区间的最大值和count都分别异或i 求出分别的和 求区间最大值可以比较容易

2019杭电多校训练(一)

比赛链接: http://acm.hdu.edu.cn/search.php?field=problem&key=2019+Multi-University+Training+Contest+1&source=1&searchmode=source hdu6582 题意: 删除某些边,让$1$到$n$的最短路径发生变化 删除某条边的费用是边的长度 分析: 先用迪杰斯特拉跑一遍整个图,满足$dis[a]+w=dis[b]$的边,肯定是最短路径上的边 选出这些边,找到一个最小割集,Di