博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【bzoj3110】[Zjoi2013]K大数查询 整体二分+树状数组区间修改
阅读量:4683 次
发布时间:2019-06-09

本文共 2380 字,大约阅读时间需要 7 分钟。

题目描述

有N个位置,M个操作。操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c。如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是多少。

输入

第一行N,M

接下来M行,每行形如1 a b c或2 a b c

输出

输出每个询问的结果

样例输入

2 5

1 1 2 1
1 1 2 2
2 1 1 2
2 1 1 1
2 1 2 3

样例输出

1

2
1


题解

整体二分+树状数组区间修改

前两天由于要讲整体二分,所以自己YY出了这种带修改的整体二分写法:

由于每次插入的权值时固定的,因此可以把修改和询问放到一起整体二分。

设 $solve(b,e,l,r)$ 表示解决 $[b,e]$ 中的修改和询问,其中:修改的权值、询问的答案都在 $[l,r]$ 内。

那么如果 $l=r$ ,则区间内所有询问的答案都等于 $l$ 。

否则设 $mid=\frac{l+r}2$ ,然后按照时间序扫一遍修改和询问。

对于修改:如果权值在 $[l,mid]$ 则丢到左区间,否则给这段区间整体+1并丢到右区间。

对于询问:如果区间和(实际含义为该次询问时区间内权值在 $[mid+1,r]$ 内的数的个数)大于等于询问的 $c$ ,说明 $[mid+1,r]$ 内有足够多的数,答案在 $[mid+1,r]$ 内,丢到右区间;否则把 $c$ 减去这个区间和,并丢到左区间。

清空数据结构,递归左右区间。注意对于左右区间也需要维护时间序。

需要实现:区间修改、区间求和,可以使用树状数组区间修改实现。具体可以参考 。

时间复杂度 $O(n\log^2n)$ ,比树套树快了10倍多。。。(当然也有可能是我当年写的不好吧)

注意本题爆int,因此需要unsigned int(比long long略快)。

#include 
#define N 50010typedef unsigned int uint;struct data{ int opt , a , b , c , id;}q[N] , t[N];int flag[N] , ans[N] , n;struct bit{ uint v[N]; inline void add(int x , int a) { int i; for(i = x ; i <= n ; i += i & -i) v[i] += a; } inline uint query(int x) { int i; uint ans = 0; for(i = x ; i ; i -= i & -i) ans += v[i]; return ans; }}A , B;inline void modify(int x , int a){ A.add(x , a) , B.add(x , a * x);}inline uint ask(int x){ return (x + 1) * A.query(x) - B.query(x);}void solve(int b , int e , int l , int r){ if(l == r) { int i; for(i = b ; i <= e ; i ++ ) if(q[i].opt == 2) ans[q[i].id] = l; return; } int mid = (l + r) >> 1 , i , lp = b - 1 , rp = e + 1; uint v; for(i = b ; i <= e ; i ++ ) { if(q[i].opt == 1) { if(q[i].c > mid) modify(q[i].a , 1) , modify(q[i].b + 1 , -1) , t[--rp] = q[i]; else t[++lp] = q[i]; } else { v = ask(q[i].b) - ask(q[i].a - 1); if((uint)q[i].c <= v) t[--rp] = q[i]; else q[i].c -= v , t[++lp] = q[i]; } } for(i = b ; i <= e ; i ++ ) if(q[i].opt == 1 && q[i].c > mid) modify(q[i].a , -1) , modify(q[i].b + 1 , 1); for(i = b ; i <= lp ; i ++ ) q[i] = t[i]; for(i = rp ; i <= e ; i ++ ) q[i] = t[e + rp - i]; solve(b , lp , l , mid) , solve(rp , e , mid + 1 , r);}int main(){ int m , i; scanf("%d%d" , &n , &m); for(i = 1 ; i <= m ; i ++ ) { scanf("%d%d%d%d" , &q[i].opt , &q[i].a , &q[i].b , &q[i].c) , q[i].id = i; if(q[i].opt == 2) flag[i] = 1; } solve(1 , m , -n , n); for(i = 1 ; i <= m ; i ++ ) if(flag[i]) printf("%d\n" , ans[i]); return 0;}

 

 

转载于:https://www.cnblogs.com/GXZlegend/p/8092824.html

你可能感兴趣的文章
敏捷开发笔记
查看>>
学前班
查看>>
关于自关联1
查看>>
hdu-1814(2-sat)
查看>>
谷歌浏览器,添加默认搜索引擎的搜索地址
查看>>
数据结构化与保存
查看>>
为什么需要Docker?
查看>>
国内5家云服务厂商 HTTPS 安全性测试横向对比
查看>>
how to control project
查看>>
转 python新手容易犯的6个错误
查看>>
第四节 -- 列表
查看>>
决策树
查看>>
团队作业
查看>>
如何避免在简单业务逻辑上面的细节上面出错
查看>>
大型网站高并发的架构演变图-摘自网络
查看>>
8丶运行及总结
查看>>
WPF中使用USERCONTROL
查看>>
图片,base64 互转
查看>>
cache—主存—辅存三级调度模拟
查看>>
Java线程的定义
查看>>