题目大意:有一些位置。这些位置上能够放若干个数字。

如今有两种操作。

1.在区间l到r上加入一个数字x

2.求出l到r上的第k大的数字是什么

思路:这样的题一看就是树套树,关键是怎么套,怎么写。(话说我也不会来着。。)最easy想到的方法就是区间线段树套一个权值线段树。可是区间线段树上的标记就会变得异常复杂。所以我们就反过来套,用权值线段树套区间线段树。

这样改动操作在外线段树上就变成了单点改动。外线段树就不用维护标记了。在里面的区间线段树上维护标记就easy多了。详细实现见代码。

CODE:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAX 50010
#define CNT (r - l + 1)
using namespace std; int total,asks; struct ValSegTree{
ValSegTree *son[2];
int cnt,c; ValSegTree() {
son[0] = son[1] = NULL;
cnt = c = 0;
}
void PushDown(int k) {
if(son[0] == NULL) son[0] = new ValSegTree();
if(son[1] == NULL) son[1] = new ValSegTree();
if(c) {
son[0]->cnt += c * (k - (k >> 1));
son[0]->c += c;
son[1]->cnt += c * (k >> 1);
son[1]->c += c;
c = 0;
}
}
void Modify(int l,int r,int x,int y) {
if(l == x && r == y) {
cnt += CNT;
c++;
return ;
}
PushDown(CNT);
int mid = (l + r) >> 1;
if(y <= mid) son[0]->Modify(l,mid,x,y);
else if(x > mid) son[1]->Modify(mid + 1,r,x,y);
else {
son[0]->Modify(l,mid,x,mid);
son[1]->Modify(mid + 1,r,mid + 1,y);
}
cnt = son[0]->cnt + son[1]->cnt;
}
int Ask(int l,int r,int x,int y) {
if(!cnt) return 0;
if(l == x && r == y) return cnt;
PushDown(CNT);
int mid = (l + r) >> 1;
if(y <= mid) return son[0]->Ask(l,mid,x,y);
if(x > mid) return son[1]->Ask(mid + 1,r,x,y);
int left = son[0]->Ask(l,mid,x,mid);
int right = son[1]->Ask(mid + 1,r,mid + 1,y);
return left + right;
}
};
struct IntSegTree{
IntSegTree *son[2];
ValSegTree *root; IntSegTree() {
son[0] = son[1] = NULL;
root = new ValSegTree();
}
void Modify(int l,int r,int _l,int _r,int x) {
root->Modify(1,total,_l,_r);
if(l == r) return ;
int mid = (l + r) >> 1;
if(son[0] == NULL) son[0] = new IntSegTree();
if(son[1] == NULL) son[1] = new IntSegTree();
if(x <= mid) son[0]->Modify(l,mid,_l,_r,x);
else son[1]->Modify(mid + 1,r,_l,_r,x);
}
int Ask(int l,int r,int _l,int _r,int k) {
if(l == r) return l;
int mid = (l + r) >> 1;
if(son[0] == NULL) son[0] = new IntSegTree();
if(son[1] == NULL) son[1] = new IntSegTree();
int temp = son[1]->root->Ask(1,total,_l,_r);
if(k > temp) return son[0]->Ask(l,mid,_l,_r,k - temp);
else return son[1]->Ask(mid + 1,r,_l,_r,k);
}
}root; int main()
{
cin >> total >> asks;
for(int flag,x,y,z,i = 1;i <= asks; ++i) {
scanf("%d%d%d%d",&flag,&x,&y,&z);
if(flag == 1) root.Modify(1,total,x,y,z);
else printf("%d\n",root.Ask(1,total,x,y,z));
}
return 0;
}

最新文章

  1. Entity Framework Linq 动态组合where条件
  2. PHP中获取当前页面的完整URL
  3. Android之Notification介绍
  4. nulls last ratio_to_report(id) over() 占比函数
  5. Cobbler自动化批量安装linux服务器的操作记录
  6. Display:Block
  7. c# 无损高质量压缩图片代码
  8. ZOJ1221 &amp;&amp; UVA567:Risk(Floyd)
  9. ThinkPHP 3 的CURD介绍
  10. SpringMVC之Controller传递JSON数据到页面
  11. Writing A Threadpool in Rust
  12. 修改国内yum源
  13. wpf研究之道-datagrid控件(1)
  14. 插件开发之360 DroidPlugin源码分析(三)Binder代理
  15. oracle 数据库 date + 1 转载
  16. Angular(02)-- Angular-CLI命令
  17. 第21月第4天 leetcode codinginterview c++
  18. map 的用法
  19. jdk源码剖析二: 对象内存布局、synchronized终极原理
  20. [py]函数中yield多次返回,延迟计算特性-杨辉三角

热门文章

  1. memcache缓存命中深入理解转载
  2. GUID的广泛使用
  3. VC Windows系统服务创建代码
  4. 13 hbase连接
  5. GET——token
  6. nginx_笔记分享_配置篇
  7. C++ AO读取shapefile的属性值
  8. C#中out的一种用法
  9. 成功启动了Apache却没有启动apache服务器
  10. 转:MFC创建多线程实例