题意

有一个长度为\(n\)的数组W;

对于每一个\(i\)(\(1<=i<=n\)),你可以选择中任意一些元素W[k] (\(1<=k<i\)),将他们的值改变为0,使得\(\sum_{j=1}^{i-1}W[j] <= m\),

所以输出n个数字,代表对于每一个\(i\),要满足以上条件,至少改变多少个元素.

想法

做这个题的时候,我一直想着怎样贪心,然后一直想不出.

一般来说第一反应应该会是先改变大的元素,但是也可以去考虑保留小的元素.

可以权值线段树+离散化.

离散化之后,用一颗权值线段树维护在前\(i-1\)个元素中,每一种元素出现了多少次.

线段树上每个节点记录每个区间内的元素出现过多少次,和每个区间内所有元素的和.

对于每一个\(i\),我们在前\(i-1\)个元素里面找到尽量多的元素,使它们的和不大于\(m-W[i]\).

在查询的时候,

如果一个节点的和小于\(m-W[i]\),那么答案直接加上这个区间上的元素的个数,即这个区间的元素都保留.

否则如果左子树上的和大于\(m-W[i]\),那么就从左子树中找应该保留哪些数,

如果左子树上的和小于\(m-W[i]\),,那么就保留左子树上的所有元素并且在右子树中找还需要哪些元素,即在右子树中查询不大于\(m-W[i]-\sum左子树上的数\).

代码

  1. #include<stdio.h>
  2. #include<vector>
  3. #include<algorithm>
  4. typedef long long ll;
  5. const int MAXN = 200100;
  6. class Node{
  7. public:
  8. int l, r, num;//l,r是区间的范围,num是区间上的数的出现次数
  9. ll val;//val是区间上的数的和
  10. Node *lson, *rson;//左右子树
  11. Node(int _l, int _r);
  12. int mid();
  13. int query(int k);
  14. void update(int pos, int _val);
  15. void clear();
  16. };
  17. Node::Node(int _l, int _r){//建线段树
  18. l = _l, r = _r, val = 0, num = 0;
  19. if(l != r){
  20. lson = new Node(l, mid());
  21. rson = new Node(mid()+1, r);
  22. }
  23. }
  24. void Node::clear(){//删除线段树
  25. if(l!=r){
  26. lson->clear();
  27. rson->clear();
  28. delete lson;
  29. delete rson;
  30. }
  31. }
  32. int Node::mid(){//求l和r的平均值
  33. return (l+r)>>1;
  34. }
  35. int Node::query(int _val){//查询,在不大于_val的情况下,应该保留哪些数字
  36. if(val <= _val) return num;//保留整个区间,直接返回num
  37. if(l == r) return (_val*num/val);//区间范围为1(即只有一个数)的时候,返回能保留多少个这个数字
  38. if(lson->val>_val) return lson->query(_val);
  39. else return lson->num+rson->query(_val-lson->val);//保留左子树上的所有数字,查询右子树
  40. }
  41. void Node::update(int pos, int _val){
  42. if(l == r){
  43. val+=_val,num++;
  44. return;
  45. }
  46. if(pos<l || pos>r) return;
  47. if(pos<=mid()) lson->update(pos, _val);
  48. else rson->update(pos, _val);
  49. num = lson->num+rson->num;
  50. val = lson->val+rson->val;
  51. }
  52. int W[MAXN], uniqueW[MAXN];
  53. int main(){
  54. int t;
  55. scanf("%d", &t);
  56. while(t--){
  57. int maxW, n, m;
  58. Node *seqTree = 0;
  59. scanf("%d%d", &n, &m);
  60. for(int i = 1; i <= n; ++i)
  61. scanf("%d", W+i), uniqueW[i] = W[i];
  62. std::sort(uniqueW+1, uniqueW+n+1);//离散化
  63. maxW = std::unique(uniqueW+1, uniqueW+n+1)-(uniqueW+1);
  64. seqTree = new Node(1, maxW);//建立一颗空的线段树,一开始没有任何的元素
  65. for(int i = 1; i <= n ; ++i){
  66. int pos = std::lower_bound(uniqueW+1, uniqueW+maxW+1, W[i])-(uniqueW);//找W[i]离散化之后的位置
  67. printf("%d ", i-seqTree->query(m-W[i])-1);//query返回的是保留的数,i-query-1就是应该改变的数
  68. seqTree->update(pos, uniqueW[pos]);//把W[i]插入线段树
  69. }
  70. seqTree->clear();//删除一下,以免mle
  71. printf("\n");
  72. }
  73. }

HDU 6609 离散化+权值线段树的更多相关文章

  1. R - Weak Pair HDU - 5877 离散化+权值线段树+dfs序 区间种类数

    R - Weak Pair HDU - 5877 离散化+权值线段树 这个题目的初步想法,首先用dfs序建一颗树,然后判断对于每一个节点进行遍历,判断他的子节点和他相乘是不是小于等于k, 这么暴力的算 ...

  2. BZOJ_3224 Tyvj 1728 普通平衡树 【离散化+权值线段树】

    一 题面 Tyvj 1728 普通平衡树 二 分析 比较明显是可以用平衡二叉搜索树(splay)做的. 用权值线段树做,前提就是要先离散化,因为权值线段树维护的值域信息. 板子. 三 AC代码 #in ...

  3. hdu 6703 array(权值线段树)

    Problem Description You are given an array a1,a2,...,an(∀i∈[1,n],1≤ai≤n). Initially, each element of ...

  4. 2019年CCPC网络赛 HDU 6703 array【权值线段树】

    题目大意:给出一个n个元素的数组A,A中所有元素都是不重复的[1,n].有两种操作:1.将pos位置的元素+1e72.查询不属于[1,r]中的最小的>=k的值.强制在线. 题解因为数组中的值唯一 ...

  5. bzoj1588: [HNOI2002]营业额统计(权值线段树)

    1588: [HNOI2002]营业额统计 Time Limit: 5 Sec  Memory Limit: 162 MBSubmit: 16863  Solved: 6789[Submit][Sta ...

  6. 线段树(单标记+离散化+扫描线+双标记)+zkw线段树+权值线段树+主席树及一些例题

    “队列进出图上的方向 线段树区间修改求出总量 可持久留下的迹象 我们 俯身欣赏” ----<膜你抄>     线段树很早就会写了,但一直没有总结,所以偶尔重写又会懵逼,所以还是要总结一下. ...

  7. HDU 6464 免费送气球 【权值线段树】(广东工业大学第十四届程序设计竞赛)

    传送门:http://acm.hdu.edu.cn/showproblem.php?pid=6464 免费送气球 Time Limit: 2000/1000 MS (Java/Others)    M ...

  8. HDU 6464 权值线段树 && HDU 6468 思维题

    免费送气球 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submi ...

  9. 区间第k大问题 权值线段树 hdu 5249

    先说下权值线段树的概念吧 权值平均树 就是指区间维护值为这个区间内点出现次数和的线段树 用这个加权线段树 解决第k大问题就很方便了 int query(int l,int r,int rt,int k ...

随机推荐

  1. JWT生成Token做登录校验

    一.JWT的优点 1.服务端不需要保存传统会话信息,没有跨域传输问题,减小服务器开销. 2.jwt构成简单,占用很少的字节,便于传输. 3.json格式通用,不同语言之间都可以使用. 二.使用JWT进 ...

  2. Centos 7下编译安装Apache

    (1)下载apr.apr-util.httpd源码包 百度云下载地址:https://pan.baidu.com/s/1HyW_9XTLhhhf5j_IuNCQsQ 提取码:pg4d (2)安装编译工 ...

  3. Python os.fdopen() 方法

    概述 os.fdopen() 方法用于通过文件描述符 fd 创建一个文件对象,并返回这个文件对象.高佣联盟 www.cgewang.com Unix, Windows上可用. 语法 fdopen()方 ...

  4. C/C++编程笔记:C语言入门知识点(二),请收藏C语言最全笔记!

    今天我们继续来学习C语言的入门知识点 11. 作用域规则 任何一种编程中,作用域是程序中定义的变量所存在的区域,超过该区域变量就不能被访问.C 语言中有三个地方可以声明变量: 在函数或块内部的局部变量 ...

  5. 经验分享:一个 30 岁的人是如何转行做程序员,进入IT行业的?

    大约一年以前,我成为了一名全职开发者,我想要总结一下这一年的经验,并且和所有人分享,一个 30 多岁的人是如何进入科技行业的: 改变职业是一件吓人的事情,有时候还会成为一件危险的事情.年龄越大,危险就 ...

  6. 5.29 省选模拟赛 树的染色 dp 最优性优化

    LINK:树的染色 考场上以为这道题要爆蛋了 没想到 推出正解来了. 反正是先写了爆搜的 爆搜最近越写越熟练了 容易想到dp 容易设出状态 f[i][j]表示以i为根的子树内白色的值为j此时黑色的值怎 ...

  7. 实验01——java模拟银行ATM系统

    用java写的一个模拟银行系统,比较初级. ATM.java package cn.tedu.yinhang; import java.util.Scanner; /** * @author 赵瑞鑫 ...

  8. MySQL8.0.20安装配置+用Navicat连接详细教程(win10,Navicat15)

    MySQL 是最流行的关系型数据库管理系统,在 WEB 应用方面 MySQL 是最好的 RDBMS(Relational Database Management System:关系数据库管理系统)应用 ...

  9. 使用docker快速搭建hive环境

    记录一下使用docker快速搭建部署hive环境 目录 写在前面 步骤 安装docker 安装docker 安装docker-compose 配置docker国内镜像源(可选) 安装git & ...

  10. RF,SVM和NN的优缺点

    1. 随机森林优缺点 随机森林(RF)是Bagging的一个扩展变体.RF在以决策树为基分类器进行集成的基础上,进一步在决策树的训练过程中引入了随机属性选择. Bagging就是对数据集训练多个基分类 ...