树套树 ---- 树状数组套权值线段树模板题 P2617 Dynamic Rankings 动态第K大
题目链接
题目大意:
给你一个数组aaa,aaa有两个操作
- 询问aaa中[l,r][l,r][l,r]区间里面第kkk小的数是哪个?
- 修改axa_xax为yyy
解题思路:
首先我们知道权值线段树是可以求第kkk小的数的,如果只有第一个问题那么就是一个主席树问题,但是主席树对于第二个问题,要修改nnn棵树时间复杂度是O(nlogn)O(nlogn)O(nlogn)的很大不行
我们知道主席树是怎么建立的?
是root[i]继承了root[i−1]的到的连续区间的权值线段树root[i]继承了root[i-1]的到的连续区间的权值线段树root[i]继承了root[i−1]的到的连续区间的权值线段树
因为你修改一个点你要把影响传到后面的所有的rootrootroot,那么开销很大
那么这个是不是很想树状数组??
树状数组修改的时候只把影响传给了后面的logloglog个节点,每次查询都要去询问logloglog个节点
那么我们的思路就来了,就是树状数组每个节点都是一个动态开点的权值线段树,现在我们要更新a5a_5a5,那么我们只有更新root[5,6,8,16]root[5,6,8,16]root[5,6,8,16]这4个节点的权值线段树
其实我们发现树状数组的作用是分层,把序列分成了logloglog层,每次这个影响只会传到每一层的一个点去
到时候查询的时候要logloglog个节点一起跳这样才能完整的统计影响
AC code
#include <bits/stdc++.h>
#define mid ((l + r) >> 1)
#define Lson rt << 1, l , mid
#define Rson rt << 1|1, mid + 1, r
#define ms(a,al) memset(a,al,sizeof(a))
#define log2(a) log(a)/log(2)
#define lowbit(x) ((-x) & x)
#define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define INF 0x3f3f3f3f
#define LLF 0x3f3f3f3f3f3f3f3f
#define endl '\n'
using namespace std;
const int N = 2e6 + 10, mod = 1e9 + 9;
const int maxn = 500010;
const long double eps = 1e-5;
const int EPS = 500 * 500;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PII;
typedef pair<ll,ll> PLL;
typedef pair<double,double> PDD;
template<typename T> void read(T &x) {x = 0;char ch = getchar();ll f = 1;while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}
template<typename T, typename... Args> void read(T &first, Args& ... args) {read(first);read(args...);
}
struct qu {char op[2];int l, r, k;
}q[maxn];
struct node {int lson, rson;int val;
}sgt[maxn * 40];
int n, root[maxn], cnt, m;
int arr[maxn];
vector<int> lis;
inline int getid(int x) {return lower_bound(lis.begin(),lis.end(),x) - lis.begin() + 1;
}inline void pushup(int rt) {sgt[rt].val = sgt[sgt[rt].lson].val + sgt[sgt[rt].rson].val;return;
}inline void insert(int &rt, int l, int r, int pos, int val = 1) {if(!rt) rt = ++ cnt;if(l == r) {sgt[rt].val += val;return;}if(pos <= mid) insert(sgt[rt].lson,l,mid,pos,val);else insert(sgt[rt].rson,mid+1,r,pos,val);pushup(rt);
}int jump[2][30], idx[2];
inline void pre_quary(int l, int r) {idx[0] = idx[1] = 0;while(l) {jump[0][++idx[0]] = root[l];l -= lowbit(l);}while(r) {jump[1][++idx[1]] = root[r];r -= lowbit(r);}
}int quary(int l, int r, int kth) {if(l == r) return l;int lsiz = 0, rsiz = 0;//log个节点一起条for(int i = 1; i <= idx[0]; ++ i) lsiz += sgt[sgt[jump[0][i]].lson].val;for(int i = 1; i <= idx[1]; ++ i) rsiz += sgt[sgt[jump[1][i]].lson].val;if(kth <= rsiz - lsiz) {for(int i = 1; i <= idx[0]; ++ i) jump[0][i] = sgt[jump[0][i]].lson;for(int i = 1; i <= idx[1]; ++ i) jump[1][i] = sgt[jump[1][i]].lson;return quary(l,mid,kth); } else {for(int i = 1; i <= idx[0]; ++ i) jump[0][i] = sgt[jump[0][i]].rson;for(int i = 1; i <= idx[1]; ++ i) jump[1][i] = sgt[jump[1][i]].rson;return quary(mid+1,r,kth-(rsiz-lsiz)); }
}int main() {IOS;cin >> n >> m;for(int i = 1; i <= n; ++ i) {cin >> arr[i];lis.push_back(arr[i]);} for(int i = 1; i <= m; ++ i){cin >> q[i].op;if(*q[i].op == 'C') cin >> q[i].l >> q[i].r, lis.push_back(q[i].r);else cin >> q[i].l >> q[i].r >> q[i].k;}sort(lis.begin(),lis.end());lis.erase(unique(lis.begin(),lis.end()),lis.end());int len = lis.size() + 1;for(int i = 1; i <= n; ++ i) {arr[i] = getid(arr[i]);//像树状数组一样跟新int j = i;while(j < len) {insert(root[j],1,len,arr[i]);j += lowbit(j);}}for(int i = 1; i <= m; ++ i) {char op = *q[i].op;if(op == 'C') {int ax = q[i].l, y = q[i].r;int j = ax;while(j < len) {insert(root[j],1,len,arr[q[i].l],-1);j += lowbit(j);} j = ax;arr[q[i].l] = getid(q[i].r);while(j < len) {insert(root[j],1,len,arr[q[i].l],1);j += lowbit(j);} } else {pre_quary(q[i].l-1,q[i].r);cout << lis[quary(1,len,q[i].k) - 1] << "\n";}}}
树套树 ---- 树状数组套权值线段树模板题 P2617 Dynamic Rankings 动态第K大相关推荐
- [权值线段树]魔道研究
题目描述 "我希望能使用更多的魔法.不对,是预定能使用啦.最终我要被大家称呼为大魔法使.为此我决定不惜一切努力." --<The Grimoire of Marisa> ...
- 树套树 ----- P1975 [国家集训队]排队(树状数组套权值线段树求动态逆序对)
解题思路: 首先我们知道交换两个数a[l]和a[r]a[l]和a[r]a[l]和a[r]影响到的区间是[l+1,r−1][l+1,r-1][l+1,r−1] 对于a[l]a[l]a[l],我们要减去[ ...
- Zju2112 Dynamic Rankings(树状数组套可持久化权值线段树)
Zju2112 Dynamic Rankings description solution code description 给定一个含有n个数的序列a[1],a[2],a[3]--a[n],程序必须 ...
- 动态区间第k小:树状数组套权值线段树
所谓树状数组套权值线段树,就是在树状树组上套权值线段树 (逃) 解析 如何解决静态区间第k小? 使用主席树就ok啦 辣么如何解决动态区间第k小嘞- 我们想想主席树为啥不能解决动态区间第k小 因为如果改 ...
- 刷题总结——序列操作(权值线段树套树状数组)
题目: 题目描述 给出序列 a1,a2,-,an(0≤ai≤109),有关序列的两种操作. 1. ai(1≤i≤n)变成 x(0≤x≤109). 2. 求 al,al+1,-,ar(1≤l≤r≤n)第 ...
- 【BZOJ3295】动态逆序对,CDQ分治/BIT套权值线段树
传送门 思路: 用来练习cdq的题目 断断续续纠结了2天 因为loli一直在考试 最后莫名乱搞了一发就A了? 实际上是考虑每一次修改对答案的贡献,即位置在1~x-1且大于x的数以及位置在x+1~n且小 ...
- 数据结构:树套树-替罪羊树套权值线段树
BZOJ3065 本题是在BZOJ上的处女A,实在不应该拿这样一道题来开头 平衡树套线段树应该是树套树问题里比较难的一种了,当然我记得还有一个替罪羊树套Trie树的题,我是不信自己能写出来的. 外层的 ...
- Minimum Inversion Number HDU - 1394(权值线段树/树状数组)
The inversion number of a given number sequence a1, a2, -, an is the number of pairs (ai, aj) that s ...
- bzoj4605 崂山白花蛇草水 权值线段树套kd树
Description Q次操作,要求资瓷 在(x,y)处放一个数字x 查询(x1,y1)到(x2,y2)矩形内第k大 Solution 非常裸的权值线段树套kd树,为了保证复杂度可以定期重构也可以平 ...
最新文章
- SQL与NoSQL区别-存储方式
- python中为什么训练数据_python训练数据时打乱训练数据与标签
- ISA Server 2006的全自动无人职守安装
- 1.Java(初级)编程教程(油管 thenewboston)学习笔记get user input
- NJ4X源码阅读分析笔记系列(三)—— nj4x-ts深入分析
- Android Studio安装genymotion模拟器
- git rebase命令(转)
- devops 三十六计_DevOps从业人员应遵循的16个博客和新闻通讯
- 当我的生活只剩下写代码时
- 酷客多小程序携手Richly network Pte Led正式进军新加坡市场
- 《符号学:原理与推演》引论
- 经济机器是如何运行的(观后感)
- 使用excel2007做聚光灯
- photoshop更改图片DPI方法
- U8-固定资产月末结账报错:BOF或EOF中有一个是真
- F. Elongated Matrix
- 数据库课程设计:利用python+MySQL+pyqt5设计一个带UI界面的书店管理系统
- 《水浒传》108将的绰号(ZZ)
- 巴菲特致股东的一封信:2002年
- R语言ROC曲线下的面积 - 评估逻辑回归中的歧视