洛谷P1774 最接近神的人_NOI导刊2010提高(02) [2017年6月计划 线段树03]
P1774 最接近神的人_NOI导刊2010提高(02)
题目描述
破解了符文之语,小FF开启了通往地下的道路。当他走到最底层时,发现正前方有一扇巨石门,门上雕刻着一幅古代人进行某种活动的图案。而石门上方用古代文写着“神的殿堂”。小FF猜想里面应该就有王室的遗产了。但现在的问题是如何打开这扇门……
仔细研究后,他发现门上的图案大概是说:古代人认为只有智者才是最容易接近神明的。而最聪明的人往往通过一种仪式选拔出来。仪式大概是指,即将隐退的智者为他的候选人写下一串无序的数字,并让他们进行一种操作,即交换序列中相邻的两个元素。而用最少的交换次数使原序列变成不下降序列的人即是下一任智者。
小FF发现门上同样有着n个数字。于是他认为打开这扇门的秘诀就是找到让这个序列变成不下降序列所需要的最小次数。但小FF不会……只好又找到了你,并答应事成之后与你三七分……
输入输出格式
输入格式:第一行为一个整数n,表示序列长度
第二行为n个整数,表示序列中每个元素。
输出格式:一个整数ans,即最少操作次数。
输入输出样例
输入样例#1:
4 2 8 0 3
输出样例#1:
3 样例说明:开始序列为2 8 0 3,目标序列为0 2 3 8,可进行三次操作的目标序列: 1.Swap (8,0):2 0 8 3 2.Swap (2,0):0 2 8 3 3.Swap (8,3):0 2 3 8
说明
对于30%的数据1≤n≤10^4。
对于100%的数据1≤n≤5*10^5;
-maxlongint≤A[i]≤maxlongint。
其实我还做了别的线段树的题,只不过太水就不放了。。
这个题也很水。。
之前写过一个用树状数组和归并排序写的,可以去看一下
这里首先离散化处理
然后 自己体会吧。。
#include <bits/stdc++.h> inline void read(long long &x) { x = 0;char ch = getchar();char c = ch; while(ch > '9' || ch < '0')c = ch, ch = getchar(); while(ch <= '9' && ch >= '0')x = x * 10 + ch - '0', ch = getchar(); if(c == '-')x = -x; } inline void read(int &x) { x = 0;char ch = getchar();char c = ch; while(ch > '9' || ch < '0')c = ch, ch = getchar(); while(ch <= '9' && ch >= '0')x = x * 10 + ch - '0', ch = getchar(); if(c == '-')x = -x; } const int INF = 0x3f3f3f3f; const int MAXN = 2000000; int n; long long stdata[MAXN],num[MAXN],cnt[MAXN]; long long ans; bool cmp(long long a, long long b) { return num[a] >= num[b]; } void modify(long long p, long long k, int o = 1, int l = 1, int r = n) { if(l == p && p == r) { stdata[o] += 1; return; } int mid = (l + r) >> 1; if(mid < p)modify(p, k, o << 1 | 1, mid + 1, r); else modify(p, k, o << 1, l, mid); stdata[o] = stdata[o << 1] + stdata[o << 1 | 1]; } long long query(long long ll, long long rr, int o = 1, int l = 1, int r = n) { if(ll <= l && rr >= r) return stdata[o]; long long mid = (l + r) >> 1; long long ans = 0; if(mid >= ll)ans += query(ll, rr, o << 1, l, mid); if(mid < rr) ans += query(ll, rr, o << 1 | 1, mid + 1, r); return ans; } int q; long long lisan[MAXN]; int main() { read(n); for(int i = 1;i <= n;i ++) { read(num[i]); cnt[i] = i; } std::sort(cnt + 1, cnt + 1 + n, cmp); //离散化 for(int i = 1;i <= n;i ++) { if(num[cnt[i]] != num[cnt[i - 1]]) lisan[cnt[i]] = ++q; else lisan[cnt[i]] = q; } for(int i = 1;i <= n;i ++) { if(lisan[i] != 1) ans += query(1, lisan[i] - 1); modify(lisan[i], 1); } printf("%lld", ans); return 0; }