Acwing 241. 楼兰图腾 树状数组 线段树(无lazy标记)
https://www.acwing.com/problem/content/243/
在完成了分配任务之后,西部 314 来到了楼兰古城的西部。
相传很久以前这片土地上(比楼兰古城还早)生活着两个部落,一个部落崇拜尖刀(V),一个部落崇拜铁锹(∧),
他们分别用 V 和 ∧ 的形状来代表各自部落的图腾。
西部 314在楼兰古城的下面发现了一幅巨大的壁画,壁画上被标记出了 n个点,
经测量发现这 n个点的水平位置和竖直位置是两两不同的。
西部 314认为这幅壁画所包含的信息与这 n 个点的相对位置有关,
因此不妨设坐标分别为 (1,y1),(2,y2),…,(n,yn),其中 y1∼yn 是 1到 n 的一个排列。
西部 314打算研究这幅壁画中包含着多少个图腾。
如果三个点 (i,yi),(j,yj),(k,yk) 满足 1≤i<j<k≤n 且 yi>yj,yj<yk,则称这三个点构成 V 图腾;
如果三个点 (i,yi),(j,yj),(k,yk) 满足 1≤i<j<k≤n且 yi<yj,yj>yk,则称这三个点构成 ∧ 图腾;
西部 314想知道,这 n个点中两个部落图腾的数目。
因此,你需要编写一个程序来求出 V 的个数和 ∧ 的个数。
输入格式
第一行一个数 n。
第二行是 n个数,分别代表 y1,y2,…,yn。
输出格式
两个数,中间用空格隔开,依次为 V 的个数和 ∧ 的个数。
数据范围
对于所有数据,n≤200000,且输出答案不会超过 int64。
y1∼yn 是 1 到 n 的一个排列。
输入样例:
5
1 5 3 2 4
输出样例:
3 4
1 树状数组解法
记录每个点左边和右边比他大的和小的点的个数
根据乘法原理,两边相乘就构成三角的个数
#define _CRT_SECURE_NO_WARNINGS
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 200010;
int tr[N],a[N];
int n;
int lowbit(int x){
return x&-x;
}
void add(int x,int c){
for(int i=x;i<=n;i+= lowbit(i)){
tr[i]+=c;
}
}
int sum(int x){
int res = 0;
for(int i =x;i;i-=lowbit(i)){
res += tr[i];
}
return res;
}
long long gr[N],low[N];
int main(){
cin >> n;
for(int i=1;i<=n;i++){
cin >> a[i]; int y = a[i];
gr[i] = (sum(n)-sum(y));
low[i] = sum(y-1);
add(y,1);
}
memset(tr,0,sizeof tr);
long long res1=0,res2=0;
for(int i=n;i>=1;i--){
int y = a[i];
res1 += gr[i]*1ll*(sum(n)-sum(y));
res2 += low[i]*1ll*sum(y-1);
add(y,1);
}
cout << res1<<" " <<res2<<endl;
return 0;
}
2 线段树 没有lazy标记解法
同树状数组一样的思路 不过代码就麻烦一些
#define _CRT_SECURE_NO_WARNINGS
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 200010;
struct NODE{
int l,r;
int cnt;
}tr[N*4];
int n;
int a[N];
void pushup(struct NODE& u,struct NODE& l,struct NODE& r){
u.cnt =l.cnt+r.cnt;
}
void pushup(int u){
pushup(tr[u],tr[u<<1],tr[u<<1|1]);
}
void add(int u,int l,int r,int a){
if(l<=tr[u].l && r>= tr[u].r){
tr[u].cnt += a;
}else{
int mid = tr[u].l + tr[u].r >>1;
if(l <=mid) add(u<<1,l,r,a);
if(r>mid) add(u<<1|1,l,r,a);
pushup(u);
}
}
int query(int u,int l,int r){
if(l<=tr[u].l && r >= tr[u].r) return tr[u].cnt;
int mid = tr[u].l+tr[u].r >> 1;
long long v = 0;
if(l<=mid) v = query(u<<1,l,r);
if(r>mid) v+= query(u<<1|1,l,r);
return v;
}
void build(int u,int l,int r){
if(l==r){
tr[u] = {l,r,0};
return;
}
tr[u].l = l; tr[u].r = r;
int mid = l+r>>1;
build(u<<1,l,mid); build(u<<1|1,mid+1,r);
pushup(u);
}
int gr[N],low[N];
int main(){
cin >>n;
build(1,1,n);
for(int i=1;i<=n;i++){
cin >>a[i];
gr[i] = query(1,a[i]+1,n);
low[i]=query(1,1,a[i]-1);
add(1,a[i],a[i],1 );
}
long long res1 =0,res2=0;
build(1,1,n);
for(int i =n;i>=1;i--){
res1 += 1ll*gr[i]*query(1,a[i]+1,n);
res2 += 1ll*low[i]*query(1,1,a[i]-1);
add(1,a[i],a[i],1 );
}
cout << res1<<" " <<res2<<endl;
return 0;
}
作 者: itdef
欢迎转帖 请保持文本完整并注明出处
技术博客 http://www.cnblogs.com/itdef/
B站算法视频题解
https://space.bilibili.com/18508846
qq 151435887
gitee https://gitee.com/def/
欢迎c c++ 算法爱好者 windows驱动爱好者 服务器程序员沟通交流
如果觉得不错,欢迎点赞,你的鼓励就是我的动力
欢迎转帖 请保持文本完整并注明出处
技术博客 http://www.cnblogs.com/itdef/
B站算法视频题解
https://space.bilibili.com/18508846
qq 151435887
gitee https://gitee.com/def/
欢迎c c++ 算法爱好者 windows驱动爱好者 服务器程序员沟通交流
如果觉得不错,欢迎点赞,你的鼓励就是我的动力


【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
2022-06-05 papamelon 242. 二分图判定(挑战程序设计竞赛)
2022-06-05 papamelon 218. 01背包问题(挑战程序设计竞赛)