1.P1908 逆序对

动态开点线段树/离散化均可解决。

动态开点线段树维护桶,每次插值时统计值域上 [ v a l , m a x _ v a l ] [val, max\_val] [val,max_val]的区间和,比其大的数的个数就是对总逆序对个数的贡献。

#include <bits/stdc++.h>
#define ll long long
using namespace std;const int maxn = 5e5, maxx = 1e9 + 7;
int sum[maxn << 5], lid[maxn << 5], rid[maxn << 5], root, tot;void push_up(int rt){sum[rt] = sum[lid[rt]] + sum[rid[rt]];
}void update(int &rt, int l, int r, int x, int value){if(!rt) rt = ++tot;if(l == r){sum[rt] += value;return;} int mid = l + r >> 1;if(x <= mid) update(lid[rt], l, mid, x, value);if(x > mid) update(rid[rt], mid + 1, r, x, value);push_up(rt);
}int query(int rt, int l, int r, int L, int R){if(!rt) return 0;if(l >= L && r <= R) return sum[rt];int mid = l + r >> 1, ans = 0;if(L <= mid) ans += query(lid[rt], l, mid, L, R);if(R > mid) ans += query(rid[rt], mid + 1, r, L, R);return ans;
}signed main(){int n = 0; cin >> n;ll ans = 0;for(int i = 1; i <= n; i++){int x = 0; cin >> x;ans += query(root, 1, maxx, x + 1, maxx);update(root, 1, maxx, x, 1);}cout << ans << endl;return 0;
}

2.P1637 三元上升子序列

题目要求在序列中求三元上升子序列的个数,先回忆一下逆序对计数的时候我们用的计数方法:建权值线段树动态插点统计。那么这个题可以采用类似的策略。

#include <bits/stdc++.h>
#define int unsigned long long
#define endl '\n'const int N = 2e5 + 10;
int tree[N << 2], ls[N << 2], rs[N << 2], a[N], b[N], len;namespace segt{#define lson rt << 1, l, mid#define rson rt << 1 | 1, mid + 1, r#define ls rt << 1#define rs rt << 1 | 1inline void push_up(int rt) { tree[rt] = tree[ls] + tree[rs]; }static void update_point(int rt, int l, int r, int pos, int val){if(l == r){tree[rt] += val;return;}int mid = l + r >> 1;if(mid >= pos) update_point(lson, pos, val);else update_point(rson, pos, val);push_up(rt);}static int query(int rt, int l, int r, int ql, int qr){if(l >= ql && r <= qr) return tree[rt];int mid = l + r >> 1, ans = 0;if(mid >= ql) ans += query(lson, ql, qr);if(mid < qr) ans += query(rson, ql, qr);return ans;}
}int smaller[N], bigger[N];inline void solve(){std::ios_base::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);int n = 0, ans = 0; std::cin >> n;for(int i = 1; i <= n; i++) std::cin >> a[i], b[i] = a[i];std::sort(a + 1, a + 1 + n);len = std::unique(a + 1, a + 1 + n) - a - 1;auto query_pos = [&](int x) { return std::lower_bound(a + 1, a + 1 + len, x) - a; };for(int i = 1; i <= n; i++){segt::update_point(1, 1, n, query_pos(b[i]), 1);int tmp = query_pos(b[i]);if(tmp == 1) continue;smaller[i] = segt::query(1, 1, n, 1, query_pos(b[i]) - 1);}memset(tree, 0, sizeof tree);for(int i = n; i >= 1; i--){segt::update_point(1, 1, n, query_pos(b[i]), 1);bigger[i] = segt::query(1, 1, n, query_pos(b[i]) + 1, n);}for(int i = 1; i <= n; i++) ans += (smaller[i] * bigger[i]);std::cout << ans << endl;
}signed main(){solve();return 0;
}

3.P6186 [NOI Online #1 提高组] 冒泡排序

可以发现冒泡排序具有性质:如果记录每个点的逆序对对数,每轮冒泡排序结束,所有非零的逆序对数都会 − 1 -1 −1。那么只需要维护一个区间和和一个区间点数和即可实现查询。

对于交换操作,首先将贡献从树上摘出来,然后分类讨论。对于 a [ x ] > a [ x + 1 ] a[x] > a[x + 1] a[x]>a[x+1]的情况,交换后会失去一个逆序对,而对于 a [ x ] < a [ x + 1 ] a[x] < a[x + 1] a[x]<a[x+1]的情况,则交换后会得到一个逆序对。同时由于是相邻数字的交换,因此交换操作不会影响其它点的逆序对数目。那么只需要讨论后再还原到树上即可。

可以全部用线段树,也可以全部用树状数组。且由于是 [ 1 , n ] [1, n] [1,n]的排列,因此不需要考虑元素相等的情况,且不需要进行离散化。

#include <bits/stdc++.h>
#define int long longconst int N = 2e5 + 10;
int a[N], b[N], cnt[N];namespace SegTree{#define lson rt << 1, l, mid#define rson rt << 1 | 1, mid + 1, rint tree[N << 2];inline void push_up(int rt){ tree[rt] = tree[rt << 1] + tree[rt << 1 | 1]; }static void update(int rt, int l, int r, int pos, int val){if(l == r){tree[rt] += val;return;}int mid = l + r >> 1;if(mid >= pos) update(lson, pos, val);else update(rson, pos, val);push_up(rt);}static int query(int rt, int l, int r, int L, int R){if(l >= L && r <= R) return tree[rt];int mid = l + r >> 1, ans = 0;if(mid >= L) ans += query(lson, L, R);if(mid < R) ans += query(rson, L, R);return ans;}
}namespace BIT{#define lowbit(x) ((x) & (-x))struct tree_array{int tree[N], len;inline void init(int n){ len = n; }inline void init(){memset(tree, 0, sizeof(tree));for(int i = 1, tmp = 0; i <= len; i++){tree[i] += a[i];tmp = i + lowbit(i);if(tmp <= len) tree[tmp] += tree[i];}}inline void update(int i, int x){if(!i) return;for(int pos = i; pos <= len; pos += lowbit(pos)) tree[pos] += x;}inline int getsum(int i, int ans = 0){for(int pos = i; pos; pos -= lowbit(pos)) ans += tree[pos];return ans;}inline int query(int l, int r){ return getsum(r) - getsum(l - 1); }}bit[2];void init(int n){ bit[0].init(n), bit[1].init(n); }
}void solve(){//std::ios_base::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);int n, m; std::cin >> n >> m;BIT::init(n);for(int i = 1; i <= n; i++) std::cin >> a[i];//auto query_pos = [&](int x){ return std::lower_bound(a + 1, a + 1 + len, x) - a; };for(int i = 1; i <= n; i++){SegTree::update(1, 1, n, a[i], 1);cnt[i] = SegTree::query(1, 1, n, a[i] + 1, n);BIT::bit[0].update(cnt[i], 1);BIT::bit[1].update(cnt[i], cnt[i]);}for(int i = 1; i <= m; i++){int op, x; std::cin >> op >> x;if(op == 1){BIT::bit[0].update(cnt[x], -1);BIT::bit[1].update(cnt[x], -cnt[x]);BIT::bit[0].update(cnt[x + 1], -1);BIT::bit[1].update(cnt[x + 1], -cnt[x + 1]);if(a[x] > a[x + 1]) --cnt[x + 1];else ++cnt[x];std::swap(cnt[x], cnt[x + 1]), std::swap(a[x], a[x + 1]);BIT::bit[0].update(cnt[x], 1);BIT::bit[1].update(cnt[x], cnt[x]);BIT::bit[0].update(cnt[x + 1], 1);BIT::bit[1].update(cnt[x + 1], cnt[x + 1]);}else if(op == 2){if(x >= n){ puts("0"); continue; }int ans1 = BIT::bit[0].query(x + 1, n);int ans2 = BIT::bit[1].query(x + 1, n);std::cout << ans2 - x * ans1 << std::endl;}   }
}signed main(){solve();return 0;
}

4.P3369【模板】普通平衡树

1.线段树解法

所有的操作都可以线段树乱搞。

#include <bits/stdc++.h>
#define endl '\n'
const int N = 1e6 + 10;namespace SegTree{#define lson rt << 1, l, mid#define rson rt << 1 | 1, mid + 1, rint tree[N << 2];inline void push_up(int rt){ tree[rt] = tree[rt << 1] + tree[rt << 1 | 1]; }static void update(int rt, int l, int r, int pos, int val){if(l == r){tree[rt] += val;return;}int mid = l + r >> 1;if(mid >= pos) update(lson, pos, val);else update(rson, pos, val);push_up(rt);}static int query(int rt, int l, int r, int L, int R){if(R < L) return 0;if(l >= L && r <= R) return tree[rt];int mid = l + r >> 1, ans = 0;if(mid >= L) ans += query(lson, L, R);if(mid < R) ans += query(rson, L, R);return ans;}static int rank(int rt, int l, int r, int rk){if(l == r) return l;int mid = l + r >> 1;if(tree[rt << 1] >= rk) return rank(lson, rk);else return rank(rson, rk - tree[rt << 1]);}
}//!SegmentTreeint opt[N], x[N], b[N], tot;inline void solve(){int n; std::cin >> n;for(int i = 1; i <= n; i++){std::cin >> opt[i] >> x[i];if(opt[i] != 4) b[++tot] = x[i];}std::sort(b + 1, b + tot + 1);for(int i = 1; i <= n; i++){if(opt[i] != 4) x[i] = std::lower_bound(b + 1, b + tot + 1, x[i]) - b;}for(int i = 1; i <= n; i++){if(opt[i] == 1) SegTree::update(1, 1, N, x[i], 1);else if(opt[i] == 2) SegTree::update(1, 1, N, x[i], -1);else if(opt[i] == 3) std::cout << SegTree::query(1, 1, N, 1, x[i] - 1) + 1 << endl;else if(opt[i] == 4) std::cout << b[SegTree::rank(1, 1, N, x[i])] << endl;else if(opt[i] == 5){int rk = SegTree::query(1, 1, N, 1, x[i] - 1);std::cout << b[SegTree::rank(1, 1, N, rk)] << endl;}else if(opt[i] == 6){int rk = SegTree::query(1, 1, N, 1, x[i]);std::cout << b[SegTree::rank(1, 1, N, rk + 1)] << endl;}}
}signed main(){solve();return 0;
}

2.Treap正解

#include <bits/stdc++.h>
#define int long long
const int N = 2e5 + 10;namespace treap{struct Treap {int lson[N], rson[N], val[N], rnd[N], size[N], w[N];int tot, ans, root;inline int Rand(){static unsigned long long seed = 114514;return (seed *= 23333ll) %= 998244553;}inline void push_up(int rt) { size[rt] = size[lson[rt]] + size[rson[rt]] + w[rt]; }void lrotate(int &rt) {int rpos = rson[rt];rson[rt] = lson[rpos], lson[rpos] = rt;size[rpos] = size[rt];push_up(rt);rt = rpos;}void rrotate(int &rt) {int lpos = lson[rt];lson[rt] = rson[lpos], rson[lpos] = rt;size[lpos] = size[rt];push_up(rt);rt = lpos;}void insert(int &rt, int x) {  // 插入if (!rt) {rt = ++tot;size[rt] = w[rt] = 1;val[rt] = x;rnd[rt] = Rand();return;}size[rt]++;if (val[rt] == x) w[rt]++;else if (val[rt] < x){insert(rson[rt], x);if (rnd[rson[rt]] < rnd[rt]) lrotate(rt);} else{insert(lson[rt], x);if (rnd[lson[rt]] < rnd[rt]) rrotate(rt);}}bool del(int &rt, int x) {  // 删除节点if (!rt) return false;if (val[rt] == x) {if (w[rt] > 1) {w[rt]--, size[rt]--;return true;}if (lson[rt] == 0 || rson[rt] == 0) {rt = lson[rt] + rson[rt];return true;} else if (rnd[lson[rt]] < rnd[rson[rt]]) {rrotate(rt);return del(rt, x);} else {lrotate(rt);return del(rt, x);}} else if (val[rt] < x) {bool flag = del(rson[rt], x);if (flag) size[rt]--;return flag;} else {bool flag = del(lson[rt], x);if (flag) size[rt]--;return flag;}}int query_rank(int rt, int x) {if (!rt) return 0;if (val[rt] == x) return size[lson[rt]] + 1;else if (x > val[rt])  return size[lson[rt]] + w[rt] + query_rank(rson[rt], x);else return query_rank(lson[rt], x);}int query_num(int rt, int x) {if (!rt) return 0;if (x <= size[lson[rt]]) return query_num(lson[rt], x);else if (x > size[lson[rt]] + w[rt]) return query_num(rson[rt], x - size[lson[rt]] - w[rt]);else return val[rt];}void query_pre(int rt, int x) {if (!rt) return;if (val[rt] < x) ans = rt, query_pre(rson[rt], x);else query_pre(lson[rt], x);}void query_nxt(int rt, int x) {if (!rt) return;if (val[rt] > x) ans = rt, query_nxt(lson[rt], x);else query_nxt(rson[rt], x);}inline int get_pre(int rt, int x){ans = 0;query_pre(rt, x);return val[ans];}inline int get_nxt(int rt, int x){ans = 0;query_nxt(rt, x);return val[ans];}}T;}inline void solve(){int n = 0; std::cin >> n;for(int i = 1; i <= n; i++){int opt, x; std::cin >> opt >> x;if(opt == 1) treap::T.insert(treap::T.root, x);else if(opt == 2) treap::T.del(treap::T.root, x);else if(opt == 3) std::cout << treap::T.query_rank(treap::T.root, x) << std::endl;else if(opt == 4) std::cout << treap::T.query_num(treap::T.root, x) << std::endl;else if(opt == 5) std::cout << treap::T.get_pre(treap::T.root, x) << std::endl;else if(opt == 6) std::cout << treap::T.get_nxt(treap::T.root, x) << std::endl;}
}signed main(){solve();return 0;
}

[线段树]打字练习2相关推荐

  1. 二逼平衡树——树套树(线段树套Splay平衡树)

    题面 Bzoj3196 解析 线段树和Splay两棵树套在一起,常数直逼inf,但最终侥幸过了 思路还是比较简单, 在原数组维护一个下标线段树,再在每一个线段树节点,维护一个对应区间的权值Splay. ...

  2. 线段树——HDU - 1698

    题目含义 就是初始化一堆数为1 可以经过操作把一个区间的数都改变 并求这堆数的总大小 题目分析 有一个 #include<iostream> #include<stdio.h> ...

  3. BZOJ.1558.[JSOI2009]等差数列(线段树 差分)

    BZOJ 洛谷 首先可以把原序列\(A_i\)转化成差分序列\(B_i\)去做. 这样对于区间加一个等差数列\((l,r,a_0,d)\),就可以转化为\(B_{l-1}\)+=\(a_0\),\(B ...

  4. 【线段树分治 线性基】luoguP3733 [HAOI2017]八纵八横

    不知道为什么bzoj没有HAOI2017 题目描述 Anihc国有n个城市,这n个城市从1~n编号,1号城市为首都.城市间初始时有m条高速公路,每条高速公路都有一个非负整数的经济影响因子,每条高速公路 ...

  5. [bzoj1582][Usaco2009 Hol]Holiday Painting 节日画画_线段树

    Holiday Painting 节日画画 bzoj-1582 Usaco-2009 Hol 题目大意:给定两个n*m的01网格图.q次操作,每次将第二个网格图的子矩阵全部变成0或1,问每一次操作后两 ...

  6. codefores 786B. Legacy(最短路,线段树优化拆点,好题)

    题目链接 B. Legacy time limit per test2 seconds memory limit per test256 megabytes inputstandard input o ...

  7. 【题解】BZOJ 3065: 带插入区间K小值——替罪羊树套线段树

    题目传送门 题解 orz vfk的题解 3065: 带插入区间K小值 系列题解 一 二 三 四 惨 一开始用了一种空间常数很大的方法,每次重构的时候merge两颗线段树,然后无限RE(其实是MLE). ...

  8. 树链剖分+线段树 HDOJ 4897 Little Devil I(小恶魔)

    题目链接 题意: 给定一棵树,每条边有黑白两种颜色,初始都是白色,现在有三种操作: 1 u v:u到v路径(最短)上的边都取成相反的颜色 2 u v:u到v路径上相邻的边都取成相反的颜色(相邻即仅有一 ...

  9. bzoj1095: [ZJOI2007]Hide 捉迷藏 线段树维护括号序列 点分治 链分治

    这题真是十分难写啊 不管是点分治还是括号序列都有一堆细节.. 点分治:时空复杂度$O(n\log^2n)$,常数巨大 主要就是3个堆的初始状态 C堆:每个节点一个,为子树中的点到它父亲的距离的堆. B ...

最新文章

  1. 生产环境主从数据同步不了?
  2. 一起学nRF51xx 8 -  Time
  3. spring-6、动态代理(cglib 与 JDK)
  4. 不错的电子书下载网站
  5. 信息学奥赛一本通(1124:矩阵加法)
  6. 今天的你将感谢_您今天感谢系统管理员了吗?
  7. 4万家公司没了!这个吸血房客的行业,终于要崩了?
  8. C语言课程设计火车订票系统存储结构设计,火车售票系统(数据结构课设)
  9. 多线程,多进程使用场景
  10. 【ACL 2019】腾讯AI Lab解读三大前沿方向及20篇入选论文
  11. matlab bar 填充花纹,科学网—使用matlab绘画柱状图,且使用不同的图案填充 - 时杰的博文...
  12. java ts视频文件合并
  13. Xshell连接服务器编写代码(windows+Xshell+阿里云主机)
  14. 【wpa_supplicant】从 assoc 动作窥伺supplicant与driver的交互(二)
  15. JDK8 Windows系统中Java HotSpot虚拟机配置参数
  16. 均匀分布的期望和方差的推导_均匀分布的期望和方差(D(X)与E(X)公式)
  17. git push报错 rejected
  18. 图片怎么修改尺寸大小?在线调整图像大小的方法
  19. 秒换算 天 时 分 秒
  20. 网上FLAC3D学习笔记

热门文章

  1. m.777lu.co wap.php,病毒穿梭/腺病毒、逆转录病毒/RNA干扰载体
  2. 大一学生WEB前端静态网页——旅游网页设计与实现(厦门旅游)
  3. Python模拟谷歌浏览器获取网页内容,反反爬虫
  4. Origin 如何输入太阳符号和约化普朗克常数
  5. YTU3189: 一个菱形
  6. aplication.yml没有图标问题
  7. 基于Arduino的自动调速风扇
  8. 气压传感器BMP280
  9. delphi 循环语句
  10. 获取当前dll自身的路径