标签:树状 query get lowbit 统计 end void ase first
借助反作弊系统,一些在月赛有抄袭作弊行为的选手被抓出来了!
这道题直接按照题意写出递归即可。写不出来的退役罢(不是我吧)
这道题有丶东西
有脑子的都知道思路:每次从第一位到倒数第二位中找出最大的数字,连带后面的数字一起取出,这样取\(\frac{n}{2}\)次就一定是最大的。
但是怎么实现啊?
因为有频繁的删除,我们不妨使用双向链表。
其实没有必要记录数组中的下标(我错在这里),只需要记录这些编号的左右对应关系即可。这样有个好处,就是你可以\(O(1)\)地访问到那个你要的任意值的龙珠。
初始化下双向链表后,我们从\(n\)枚举到\(1\),如果这个节点后面还有的话就直接用了,接下来就是naive的链表删除环节了。。。
我sbsb在想成询问区间\([1,n-1]\)的最大值并删除两个数,导致想得非常乱还不会。。。
代码很简单:
#include<bits/stdc++.h>
using std::cin;
using std::cout;
using std::endl;
const int maxn = 100005;
int a[maxn], n;
struct Nodes {
int val, idx;
Nodes(int val, int idx): val(val), idx(idx){}
bool operator < (const Nodes &rhs) const {
return val > rhs.val;
}
};
std::set<Nodes> s;
int left[maxn], right[maxn], first, last;
int main() {
cin >> n;
for(int i = 1; i <= n; i++) {
cin >> a[i];
s.insert(Nodes(a[i], i));
if(i > 1) left[i] = i - 1;
if(i < n) right[i] = i + 1;
}
first = 1; last = n;
for(int i = 1; i <= n / 2; i++) {
// get
int idx = -1;
std::vector<Nodes> sorry;
for(std::set<Nodes>::iterator it = s.begin(); it != s.end(); it++) {
if(it->idx == last) sorry.push_back(*it);
else {
idx = it->idx; break;
}
}
for(auto it: sorry) s.insert(it);
cout << a[idx] << ' ' << a[right[idx]] << ' ';
s.erase(Nodes(a[idx], idx));
s.erase(Nodes(a[right[idx]], right[idx]));
if(right[idx] == last) {
// 右边没有了
if(left[idx] == 0) break;// 左边也没有了
else {
// 左边还有
last = left[idx];
right[last] = 0;
}
} else {
// 右边还有
if(left[idx] == 0) {
// 左边没有了
first = right[right[idx]];
left[first] = 0;
} else {
// 左边还有
right[left[idx]] = right[right[idx]];
}
}
}
return 0;
}
讲道理我觉得比B好写(前提是当你复习过树状数组求逆序对)
我们当然不用枚举出\(\frac{n (n+1)}{2}\)个区间,按照贡献法,设一个逆序对\((a_i,a_j)\),显然它会被算\(i \times (n - j + 1)\)次。
借鉴一下树状数组的思路,它的思路是把数字离散化后按照桶的思想统计数值比它大,还比它早添加的数字个数,因此在树状数组中统一+1。
我们同样是这个思路,枚举前面逆序对的\(a_j\),树状数组加上原来的下标\(i\),每次也是同样的查询,产生的贡献是查询结果乘以\(n -j + 1\)。
注意了,离散化是包括去重的。。。应该只有我这种菜鸡忘了。
这道题居然要用__int128
。。。
代码:
#include<bits/stdc++.h>
#define ll __int128
const ll maxn = 1000005;
ll a[maxn], b[maxn];
ll n;
struct BIT {
ll c[maxn];
inline ll lowbit(int x) {
return x & -x;
}
void add(ll i, ll x) {
for(; i <= n; i += lowbit(i)) c[i] += x;
}
ll query(int i) {
ll ret = 0;
for(; i; i -= lowbit(i)) ret += c[i];
return ret;
}
} c;
ll read() {
ll ans = 0, s = 1;
char ch = getchar();
while(ch > '9' || ch < '0') {
if(ch == '-') s = -1;
ch = getchar();
}
while(ch >= '0' && ch <= '9') {
ans = ans * 10 + ch - '0';
ch = getchar();
}
return s * ans;
}
void print(ll x) {
if(x >= 10) print(x / 10);
putchar((x % 10) + '0');
}
int main() {
ll ans = 0;
n = read();
for(ll i = 1; i <= n; i++) {
b[i] = a[i] = read();
}
std::sort(b + 1, b + n + 1);
ll len = std::unique(b + 1, b + n + 1) - b - 1;
for(ll i = 1; i <= n; i++) {
ll pos = std::lower_bound(b + 1, b + len + 1, a[i]) - b;
c.add(pos, i);
ll temp = c.query(n) - c.query(pos);
ans += temp * (n - i + 1ll);
}
print(ans);
putchar('\n');
return 0;
}
这辈子不可能写压轴题
标签:树状 query get lowbit 统计 end void ase first
原文地址:https://www.cnblogs.com/Garen-Wang/p/11273439.html