#P2070. 第2题-小明数组
-
1000ms
Tried: 21
Accepted: 9
Difficulty: 7
所属公司 :
阿里
时间 :2024年9月14日-阿里淘天
-
算法标签>树状数组
第2题-小明数组
树状数组
前置知识树状数组https://oi-wiki.org/ds/fenwick/ 对于目前的i只需要利用map映射f(1,i,ai)的值就可以知道也就是mp[a[i]],怎么快速知道有多少个f(j,n,aj)小于mp[a[i]],用一个树状数组维护,就可以直接区间查找了. 具体做法 add(f(j,n,aj),1),1<=j<=n 枚举i然后add(f(i,n,ai),−1)ans+=query(1,f(i,n,ai)−1) 整体时间复杂度o(nlog2n)
代码如下
cpp
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define N 200000
int t1[N];
int lowbit(int x) {
return ((-x)&x);
}
void add(int x, int y) {
for (int i = x; i < N; i += lowbit(i)) {
t1[i] += y;
}
}
int query(int r) {//f(j,n,aj)<=r
int res = 0;
for (int i = r; i; i -= lowbit(i)) {
res += t1[i];
}
return res;
}
int a[N];
int suf[N];
signed main() {
ios::sync_with_stdio(0);
cin.tie(0);
vector<char>c(27);
int n;
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
map<int, int>mp;
for (int i = n; i >= 1; i--) {
mp[a[i]] += 1;
suf[i] = mp[a[i]];
add(suf[i], 1);
}
mp.clear();
long long ans = 0;
for (int i = 1; i <= n; i++) {
mp[a[i]] += 1;//f(1,i,ai)
add(suf[i], - 1);
ans += query(mp[a[i]] - 1);
}
cout << ans << '\n';
}
python
def lowbit(x):
return x & -x
def add(x, y, t1, N):
while x < N:
t1[x] += y
x += lowbit(x)
def query(r, t1):
res = 0
while r > 0:
res += t1[r]
r -= lowbit(r)
return res
def main():
import sys
input = sys.stdin.read
data = input().split()
n = int(data[0])
a = list(map(int, data[1:n+1]))
N = 200000
t1 = [0] * N
suf = [0] * (n + 1)
mp = {}
# Calculate suffix frequencies
for i in range(n - 1, -1, -1):
mp[a[i]] = mp.get(a[i], 0) + 1
suf[i + 1] = mp[a[i]]
add(suf[i + 1], 1, t1, N)
mp.clear()
ans = 0
# Calculate the result
for i in range(1, n + 1):
mp[a[i - 1]] = mp.get(a[i - 1], 0) + 1
add(suf[i], -1, t1, N)
ans += query(mp[a[i - 1]] - 1, t1)
print(ans)
if __name__ == "__main__":
main()
java
import java.io.*;
import java.util.*;
public class Main {
static class Node {
long sum;
long pre;
Node(long sum, long pre) {
this.sum = sum;
this.pre = pre;
}
}
static class Pair<T, U> {
T first;
U second;
Pair(T first, U second) {
this.first = first;
this.second = second;
}
}
static Node merge(Node a, Node b) {
return new Node(a.sum + b.sum, Math.max(a.pre, a.sum + b.pre));
}
static Pair<Integer, Node>[][] f = new Pair[200005][31];
static long[] nxt = new long[200005];
static long[] a = new long[200005];
static int n, q;
static long x, y;
static void init() {
for (int i = 1; i <= n; i++) {
f[i][0] = new Pair<>((int) nxt[i], new Node(0, 0));
long w = a[(int) nxt[i]] > a[i] ? x : y;
f[i][0].second = new Node(w, w);
}
for (int i = 1; i < 30; i++) {
for (int j = 1; j <= n; j++) {
int v = f[j][i - 1].first;
f[j][i] = new Pair<>(f[v][i - 1].first, merge(f[j][i - 1].second, f[v][i - 1].second));
}
}
}
static long ask(int u, int k) {
Node r = new Node(0, 0);
for (int i = 29; i >= 0; i--) {
if ((k >> i & 1) == 1) {
r = merge(r, f[u][i].second);
u = f[u][i].first;
}
}
return r.pre;
}
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
//BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
Scanner scanner = new Scanner(System.in);
n = scanner.nextInt();
q = scanner.nextInt();
x = scanner.nextInt();
y = scanner.nextInt();
for (int i = 1; i <= n; i++) {
nxt[i] = scanner.nextInt();
// System.out.println(nxt[i]);
}
for (int i = 1; i <= n; i++) {
a[i] = scanner.nextInt();
}
init();
while (q-- > 0) {
int u = scanner.nextInt();
int k = scanner.nextInt();
System.out.println(ask(u, k));
}
}
}
题目内容
小明有一个长度为n的数组a,记f(l,r,x)为区间[l,r]内x的出现次数。
现在小明想知道有多少对i<j满足f(1,i,ai)>f(j,n,aj)。
输入描述
第一行输入一个整数 n
第二行n个整数a1,a2,...,an。
1≤n≤105
1≤ai≤109
输出描述
输出一个整数表示答案。
样例1
输入
6
1 2 1 2 2 1
输出
5
说明
存在以下五对(i,j)满足条件:(3,5)(3,6)(4,5)(4,6)(5,6)
样例2
输入
输出