Luogu P1637 三元上升子序列【权值线段树】By cellur925
emmm..不开结构体的线段树真香!
首先我们知道“三元上升子序列”的个数就是对于序列中的每个数,它左边比他小的数*它右边比他大的数。但是如何快速求出这两个数?
我们用到权值线段树来维护。一般我们的线段树都是以下标延伸的,但是这里我们用的是权值,一般需要离散化,效果相当于一个桶。
这部分讲解请移步绝世好文
第一次我们从\(1\)$n$循环是为了找它左边的,而找比他小的值是在线段树的$1$\(seq[i]-1\)中找。第二次我们从\(n\)$1$循环是为了找它右边的,而找比他大的值是用在线段树的$seq[i]+1$\(n\)中找实现的。
不用结构体因为方便清空,\(tong\)数组记录线段树的权值,注意开\(4\)倍。
#include<cstdio>
#include<algorithm>
#include<cstring>
#define maxn 100090
using namespace std;
typedef long long ll;
int n;
ll ans,sma[maxn],bigg[maxn];
int seq[maxn],tmp[maxn],tong[maxn<<2];
int ask(int p,int l,int r,int L,int R)
{
if(L<=l&&r<=R) return tong[p];
int mid=(l+r)>>1,qwq=0;
if(L<=mid) qwq+=ask(p<<1,l,mid,L,R);
if(R>mid) qwq+=ask(p<<1|1,mid+1,r,L,R);
return qwq;
}
void change(int p,int l,int r,int x)
{
if(l==x&&r==x)
{
tong[p]++;
return ;
}
int mid=(l+r)>>1;
if(x<=mid) change(p<<1,l,mid,x);
else if(x>mid) change(p<<1|1,mid+1,r,x);
tong[p]=tong[p<<1]+tong[p<<1|1];
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&seq[i]),tmp[i]=seq[i];
sort(tmp+1,tmp+1+n);
int m=unique(tmp+1,tmp+1+n)-(tmp+1);
for(int i=1;i<=n;i++)
seq[i]=lower_bound(tmp+1,tmp+1+m,seq[i])-tmp;
for(int i=1;i<=n;i++)
{
if(seq[i]!=1) sma[i]=ask(1,1,n,1,seq[i]-1);
change(1,1,n,seq[i]);
}
memset(tong,0,sizeof(tong));
for(int i=n;i>=1;i--)
{
if(seq[i]!=n) bigg[i]=ask(1,1,n,seq[i]+1,n);
change(1,1,n,seq[i]);
}
for(int i=1;i<=n;i++)
ans+=sma[i]*bigg[i];
printf("%lld\n",ans);
return 0;
}
用线段树求逆序对是同理的,只需要求出每个序列中的位置的左边比它大的数个数就行了。
#include<cstdio>
#include<algorithm>
#include<cstring>
#define maxn 500090
using namespace std;
typedef long long ll;
int n;
ll ans,lef[maxn];
int tmp[maxn],seq[maxn],tong[maxn<<2];
int ask(int p,int l,int r,int L,int R)
{
if(L<=l&&r<=R) return tong[p];
int mid=(l+r)>>1,qwq=0;
if(L<=mid) qwq+=ask(p<<1,l,mid,L,R);
if(R>mid) qwq+=ask(p<<1|1,mid+1,r,L,R);
return qwq;
}
void change(int p,int l,int r,int x)
{
if(l==x&&r==x)
{
tong[p]++;
return ;
}
int mid=(l+r)>>1;
if(x<=mid) change(p<<1,l,mid,x);
else if(x>mid) change(p<<1|1,mid+1,r,x);
tong[p]=tong[p<<1]+tong[p<<1|1];
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&seq[i]),tmp[i]=seq[i];
sort(tmp+1,tmp+1+n);
int m=unique(tmp+1,tmp+1+n)-(tmp+1);
for(int i=1;i<=n;i++)
seq[i]=lower_bound(tmp+1,tmp+1+m,seq[i])-tmp;
for(int i=1;i<=n;i++)
{
if(seq[i]!=n) lef[i]=ask(1,1,n,seq[i]+1,n);
change(1,1,n,seq[i]);
}
for(int i=1;i<=n;i++)
ans+=lef[i];
printf("%lld\n",ans);
return 0;
}
Luogu P1637 三元上升子序列【权值线段树】By cellur925的更多相关文章
- [BZOJ 3295] [luogu 3157] [CQOI2011]动态逆序对(树状数组套权值线段树)
[BZOJ 3295] [luogu 3157] [CQOI2011] 动态逆序对 (树状数组套权值线段树) 题面 给出一个长度为n的排列,每次操作删除一个数,求每次操作前排列逆序对的个数 分析 每次 ...
- [BZOJ 3110] [luogu 3332] [ZJOI 2013]k大数查询(权值线段树套线段树)
[BZOJ 3110] [luogu 3332] [ZJOI 2013]k大数查询(权值线段树套线段树) 题面 原题面有点歧义,不过从样例可以看出来真正的意思 有n个位置,每个位置可以看做一个集合. ...
- bzoj 4627: [BeiJing2016]回转寿司 -- 权值线段树
4627: [BeiJing2016]回转寿司 Time Limit: 10 Sec Memory Limit: 256 MB Description 酷爱日料的小Z经常光顾学校东门外的回转寿司店. ...
- 【HDU6701】Make Rounddog Happy【权值线段树+双向单调队列】
题意:给你一个序列,求满足要求的子序列个数,其中要求为: 1.子序列的max-子序列长度len<=k 2.子序列中不出现重复的数字 题解:首先看到子序列max,很容易想到枚举最大值然后分治,这个 ...
- 【树状数组套权值线段树】bzoj1901 Zju2112 Dynamic Rankings
谁再管这玩意叫树状数组套主席树我跟谁急 明明就是树状数组的每个结点维护一棵动态开结点的权值线段树而已 好吧,其实只有一个指针,指向该结点的权值线段树的当前结点 每次查询之前,要让指针指向根结点 不同结 ...
- 【BZOJ-2892&1171】强袭作战&大sz的游戏 权值线段树+单调队列+标记永久化+DP
2892: 强袭作战 Time Limit: 50 Sec Memory Limit: 512 MBSubmit: 45 Solved: 30[Submit][Status][Discuss] D ...
- BZOJ 3110 ZJOI 2013 K大数查询 树套树(权值线段树套区间线段树)
题目大意:有一些位置.这些位置上能够放若干个数字. 如今有两种操作. 1.在区间l到r上加入一个数字x 2.求出l到r上的第k大的数字是什么 思路:这样的题一看就是树套树,关键是怎么套,怎么写.(话说 ...
- 动态求区间K大值(权值线段树)
我们知道我们可以通过主席树来维护静态区间第K大值.我们又知道主席树满足可加性,所以我们可以用树状数组来维护主席树,树状数组的每一个节点都可以开一颗主席树,然后一起做. 我们注意到树状数组的每一棵树都和 ...
- 线段树(单标记+离散化+扫描线+双标记)+zkw线段树+权值线段树+主席树及一些例题
“队列进出图上的方向 线段树区间修改求出总量 可持久留下的迹象 我们 俯身欣赏” ----<膜你抄> 线段树很早就会写了,但一直没有总结,所以偶尔重写又会懵逼,所以还是要总结一下. ...
随机推荐
- Java对象 的创建与构造方法
一.创建对象的四种方法: a. new语句: b. 利用反射,调用描述类的Class对象的newInstance()实例方法: c. 调用对象的clone(): d. 反序列化: 其中new 和 ne ...
- CodeForces - 540B School Marks —— 贪心
题目链接:https://vjudge.net/contest/226823#problem/B Little Vova studies programming in an elite school. ...
- Spring Boot2.0之热部署原理
所谓的热部署:比如项目的热部署,就是在应用程序在不停止的情况下,实现新的部署 原理: 实用类加载器(classloader重新读取字节码文件到jvm内存) 如何纯手写一个热部署功能: 1.监听 cla ...
- 动态创建TeeChart的简便方法
最近在项目中使用Teechart ocx版本替换了labview的老版本控件,显示效果和效率均有提高,但是却遇到多线程下报access violation的问题. 翻遍大小论坛,最后在官网论坛找到相同 ...
- lsnrctl启动报错,Linux Error: 29: Illegal seek
[oracle@phydb admin]$ lsnrctl startLSNRCTL for Linux: Version 11.2.0.1.0 - Production on 15-SEP-2014 ...
- BZOJ3648:寝室管理
浅谈树分治:https://www.cnblogs.com/AKMer/p/10014803.html 题目传送门:https://www.lydsy.com/JudgeOnline/problem. ...
- Hadoop安装全教程 Ubuntu14.04+Java1.8.0+Hadoop2.7.6
最近听了一个关于大数据的大牛的经验分享,在分享的最后大牛给我们一个他之前写好的关于大数据和地理应用demo.这个demo需要在Linux环境上搭建Hadoop平台.这次就简单的分享一下我关于在 Lin ...
- 关于UML图的生成
想把一个java工程生成UML图非常简单,之前我的eclipse是4.2.0的,没有对应的GEF,所以我索性就直接把工程粘到了My Eclipse中,因为My Eclipse里面有UML自动生成的功能 ...
- SQL大全(1)
实用SQL语句大全 一.基础 1.创建数据库 create database 数据库名 2.删除数据库 drop database 数据库名 3.增加列 alter table 表名 add 列名 类 ...
- [allmake] -- 交叉编译原来如此简单
原创作品,允许转载,转载时请务必以超链接形式标明文章原始出处.作者信息和本声明.否则将追究法律责任.:http://www.cnblogs.com/johnd/p/5060530.html 作者:Jo ...