首页 > 其他分享 >lgP1637 三元上升子序列

lgP1637 三元上升子序列

时间:2024-07-14 12:51:29浏览次数:10  
标签:node lgP1637 return int TYPE son 序列 三元 data

给定n个整数的序列A,求存在多少个三元上升子序列,即满足i<j<k并且a[i]<a[j]<a[k]。

分析:用平衡树维护两侧元素,然后枚举中间元素即可。

#include <bits/stdc++.h>
using llong = long long;

template <typename TYPE>
struct Treap {
	struct Node {
		TYPE data, sum;
		int rnd, siz, dup, son[2];
		void init(const TYPE & d) {
			data = sum = d;
			rnd = rand();
			siz = dup = 1;
			son[0] = son[1] = 0;
		}
	};
	Treap(size_t sz, bool multi, bool needSum=false):multiple(multi),needsum(needSum) {
		node.resize(sz + 1);
		reset();
	}
	int newnode(const TYPE & d) {
		total += 1;
		node[total].init(d);
		return total;
	}
	void reset() { root = total = 0; }
	void maintain(int x) {
		node[x].siz = node[x].dup;
		if (needsum) node[x].sum = node[x].data * node[x].dup;
		if (node[x].son[0]) {
			node[x].siz += node[node[x].son[0]].siz;
			if (needsum) node[x].sum += node[node[x].son[0]].sum;
		}
		if (node[x].son[1]) {
			node[x].siz += node[node[x].son[1]].siz;
			if (needsum) node[x].sum += node[node[x].son[1]].sum;
		}
	}
	void rotate(int d, int &r) {
		int k = node[r].son[d^1];
		node[r].son[d^1] = node[k].son[d];
		node[k].son[d] = r;
		maintain(r);
		maintain(k);
		r = k;
	}
	void insert(const TYPE &data, int &r, bool &ans) {
		if (r) {
			if (!(data < node[r].data) && !(node[r].data < data)) {
				ans = false;
				if (multiple) {
					node[r].dup += 1;
					maintain(r);
				}
			} else {
				int d = data < node[r].data ? 0 : 1;
				insert(data, node[r].son[d], ans);
				if (node[node[r].son[d]].rnd > node[r].rnd) {
					rotate(d^1, r);
				} else {
					maintain(r);
				}
			}
		} else {
			r = newnode(data);
		}
	}
	void getkth(int k, int r, TYPE& data) {
		int x = node[r].son[0] ? node[node[r].son[0]].siz : 0;
		int y = node[r].dup;
		if (k <= x) {
			getkth(k, node[r].son[0], data);
		} else if (k <= x + y) {
			data = node[r].data;
		} else {
			getkth(k-x-y, node[r].son[1], data);
		}
	}
	TYPE getksum(int k, int r) {
		if (k <= 0 || r == 0) return 0;
		int x = node[r].son[0] ? node[node[r].son[0]].siz : 0;
		int y = node[r].dup;
		if (k <= x) return getksum(k, node[r].son[0]);
		if (k <= x+y) return node[node[r].son[0]].sum + node[r].data * (k-x);
		return node[node[r].son[0]].sum + node[r].data * y + getksum(k-x-y,node[r].son[1]);
	}
	void erase(const TYPE& data, int & r) {
		if (r == 0) return;
		int d = -1;
		if (data < node[r].data) {
			d = 0;
		} else if (node[r].data < data) {
			d = 1;
		}
		if (d == -1) {
			node[r].dup -= 1;
			if (node[r].dup > 0) {
				maintain(r);
			} else {
				if (node[r].son[0] == 0) {
					r = node[r].son[1];
				} else if (node[r].son[1] == 0) {
					r = node[r].son[0];
				} else {
					int dd = node[node[r].son[0]].rnd > node[node[r].son[1]].rnd ? 1 : 0;
					rotate(dd, r);
					erase(data, node[r].son[dd]);
				}
			}
		} else {
			erase(data, node[r].son[d]);
		}
		if (r) maintain(r);
	}
	int ltcnt(const TYPE& data, int r) {
		if (r == 0) return 0;
		int x = node[r].son[0] ? node[node[r].son[0]].siz : 0;
		if (data < node[r].data) {
			return ltcnt(data, node[r].son[0]);
		}
		if (!(data < node[r].data) && !(node[r].data < data)) {
			return x;
		}
		return x + node[r].dup + ltcnt(data, node[r].son[1]);
	}
	int gtcnt(const TYPE& data, int r) {
		if (r == 0) return 0;
		int x = node[r].son[1] ? node[node[r].son[1]].siz : 0;
		if (data > node[r].data) {
			return gtcnt(data, node[r].son[1]);
		}
		if (!(data < node[r].data) && !(node[r].data < data)) {
			return x;
		}
		return x + node[r].dup + gtcnt(data, node[r].son[0]);
	}
	int count(const TYPE& data, int r) {
		if (r == 0) return 0;
		if (data < node[r].data) return count(data, node[r].son[0]);
		if (node[r].data < data) return count(data, node[r].son[1]);
		return node[r].dup;
	}
	void prev(const TYPE& data, int r, TYPE& result, bool& ret) {
		if (r) {
			if (node[r].data < data) {
				if (ret) {
					result = std::max(result, node[r].data);
				} else {
					result = node[r].data;
					ret = true;
				}
				prev(data, node[r].son[1], result, ret);
			} else {
				prev(data, node[r].son[0], result, ret);
			}
		}
	}
	void next(const TYPE& data, int r, TYPE& result, bool& ret) {
		if (r) {
			if (data < node[r].data) {
				if (ret) {
					result = std::min(result, node[r].data);
				} else {
					result = node[r].data;
					ret = true;
				}
				next(data, node[r].son[0], result, ret);
			} else {
				next(data, node[r].son[1], result, ret);
			}
		}
	}
	std::vector<Node> node;
	int root;
	int total;
	bool multiple;
	bool needsum;
	bool insert(const TYPE& data) {
		bool ret = true;
		insert(data, root, ret);
		return ret;
	}
	bool kth(int k, TYPE &data) {
		if (!root || k <= 0 || k >= node[root].siz)
			return false;
		getkth(k, root, data);
		return true;
	}
	TYPE ksum(int k) {
		assert(root && k>0 && k<node[root].siz);
		return getksum(k, root);
	}
	int count(const TYPE &data) {
		return count(data, root);
	}
	int size() const {
		return root ? node[root].siz : 0;
	}
	void erase(const TYPE& data) {
		return erase(data, root);
	}
	int ltcnt(const TYPE& data) {
		return ltcnt(data, root);
	}
	int gtcnt(const TYPE& data) {
		return gtcnt(data, root);
	}
	int lecnt(const TYPE& data) {
		return size() - gtcnt(data, root);
	}
	int gecnt(const TYPE& data) {
		return size() - ltcnt(data, root);
	}
	bool prev(const TYPE& data, TYPE& result) {
		bool ret = false;
		prev(data, root, result, ret);
		return ret;
	}
	bool next(const TYPE& data, TYPE& result) {
		bool ret = false;
		next(data, root, result, ret);
		return ret;
	}
};

void solve() {
	int n;
	std::cin >> n;
	std::vector<int> A(n);
	for (int i = 0; i < n; i++) {
		std::cin >> A[i];
	}
	Treap<int> tr1(n,1,0), tr2(n,1,0);
	for (int i = 0; i < n; i++) {
		tr2.insert(A[i]);
	}
	llong ans = 0;
	for (int i = 0; i < n; i++) {
		tr2.erase(A[i]);
		ans += 1LL * tr1.ltcnt(A[i]) * tr2.gtcnt(A[i]);
		tr1.insert(A[i]);
	}
	std::cout << ans << "\n";
}

int main() {
	std::cin.tie(0)->sync_with_stdio(0);
	int t = 1;
	while (t--) solve();
	return 0;
}

标签:node,lgP1637,return,int,TYPE,son,序列,三元,data
From: https://www.cnblogs.com/chenfy27/p/18301364

相关文章

  • 运算符的关系,什么叫一元运算符,二元运算符,三元运算符,运算符优先级,以及运算符的
    按照操作数个数区分:一元运算符:一元运算符只需要一个操作数。常见的一元运算符有:1.递增和递减运算符:++和--,用于对操作数进行增加或减少1。2.正负号运算符:+和-,用于表示正负数。3.逻辑非运算符:!,用于对布尔值进行取反。二元运算符:二元运算符需要两个操作数。常见的二元运......
  • 三元运算符 栈 堆 隐式转换 笔记
    是什么:相当于if语句的语法糖代码示例:std::stringrank=level>10?"Master":"Begining";判断条件?为真保留:为假保留;可以嵌套使用,最好别用看的头疼;栈通常非常小通常为1兆2兆;浅要提及堆上飞陪比栈花费更多时间,而且要手动释放内存若对象太大或要显式地控制对象的生存期,就在堆......
  • Python序列
    Python序列在Python中,序列类型包括字符串、列表、元组、集合和字典,这些序列支持以下几种通用的操作,但比较特殊的是,集合和字典不支持索引、切片、相加和相乘操作。字符串也是一种常见的序列,它也可以直接通过索引访问字符串内的字符。序列索引序列中,每个元素都有属于自己的编......
  • Shiro550反序列化漏洞分析
    shiro搭建教程可以在网上自行搜索漏洞发现进入shiro界面后,burp抓包,选择rememberme并进行登录。观察burp抓到的包登录之后服务器返回一个CookieRememberme之后用户的访问都带着这个Cookie这个Cookie很长,可能会在里面存在一定的信息源码审计接下来去shiro源码中,看......
  • 时间序列分析论文翻译与笔记:The correct way to start an Exponential Moving Average
            在之前的笔记中,我们初步认识了指数移动平均(指数加权移动平均),本文将通过翻译一篇DavidOwen 在2017年的一篇博客,讨论如何确保移动平均数能够通过识别记录信息的时长,来适应新的信息。原文链接:点击这里(原文的代码为R,本文将补充py代码)目录如何正确地开始指数移......
  • Java中的反序列化详解
    Java中的反序列化详解大家好,我是微赚淘客系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿!1.什么是反序列化?反序列化是将对象的字节序列转换回对象的过程。在Java中,对象序列化是将对象转换为字节序列以便存储或传输,而反序列化则是将这些字节序列重新转换为对象。2.Java中......
  • 经济学:动态模型平均(DMA)、动态模型选择(DMS)、ARIMA、TVP预测原油时间序列价格|附代
    全文链接:http://tecdat.cn/?p=22458最近我们被客户要求撰写关于动态模型平均的研究报告,包括一些图形和统计输出。本文提供了一个经济案例。着重于原油市场的例子。简要地提供了在经济学中使用模型平均和贝叶斯方法的论据,使用了动态模型平均法(DMA),并与ARIMA、TVP等方法进行比较简......
  • R语言ARMA-GARCH模型金融产品价格实证分析黄金价格时间序列|附代码数据
    全文链接:http://tecdat.cn/?p=32677原文出处:拓端数据部落公众号最近我们被客户要求撰写关于ARMA-GARCH的研究报告,包括一些图形和统计输出。研究黄金价格的动态演变过程至关重要。文中以黄金交易市场下午定盘价格为基础,帮助客户利用时间序列的相关理论,建立了黄金价格的ARMA-GA......
  • 时间序列分析方法汇总对比及优缺点和适用情况(上)--1. 移动平均 2. 指数平滑 3. 自回归
    目录1.移动平均(MovingAverage)2.指数平滑(ExponentialSmoothing)3.自回归模型(AutoregressiveModel,AR)4.移动平均模型(MovingAverageModel,MA)5.自回归移动平均模型(ARMA) 1.移动平均(MovingAverage)移动平均是平滑时间序列的一种技术,旨在通过消除短期波动来揭示......
  • ROME 反序列化
    ROME反序列化rome是什么ROME是主要用于解析RSS和Atom种子的一个Java框架。ROME是一个可以兼容多种格式的feeds解析器,可以从一种格式转换成另一种格式,也可返回指定格式或Java对象。ROME兼容了RSS(0.90,0.91,0.92,0.93,0.94,1.0,2.0),Atom0.3以及Atom1.0fe......