简要题解
前四道题均为洛谷原题,大家自行查阅题解即可。
还原排列
观察
不妨倒着考虑。
考虑
-
- 另一种情况,
s_{n - 1} 是一段连续1 \sim k_2 的和减去p_n ,也就是p_n \leq k_2 ,那这种情况我们如何计算呢?
考虑维护一个线段树,线段树存的是
我们计算
计算出
这样复杂度是两个
std:(暂时只有线段树上二分版)
#include <iostream>
#include <cstdio>
#include <algorithm>
#define ls rt << 1
#define rs rt << 1 | 1
#define ll long long
using namespace std;
const ll N = 1e6 + 10;
ll n;
ll s[N], p[N];
ll t[N << 2];
inline ll read(){
ll x = 0, f = 1;
char ch = getchar();
while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
while(ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
return x * f;
}
inline void pushup(ll rt){
t[rt] = t[ls] + t[rs];
}
void build(ll l, ll r, ll rt){
if(l == r){
t[rt] = l;
return;
}
ll mid = (l + r) >> 1;
build(l, mid, rt << 1);
build(mid + 1, r, rt << 1 | 1);
pushup(rt);
}
ll query(ll k, ll l, ll r, ll rt){
if(l == r)
return l;
ll mid = (l + r) >> 1;
if(k <= t[ls]) return query(k, l, mid, ls);
else return query(k - t[ls], mid + 1, r, rs);
}
void remove(ll pos, ll l, ll r, ll rt){
if(l == r){
t[rt] = 0ll;
return;
}
ll mid = (l + r) >> 1;
if(pos <= mid) remove(pos, l, mid, ls);
else remove(pos, mid + 1, r, rs);
pushup(rt);
}
signed main(){
n = read();
for(ll i = 1; i <= n; i++)
s[i] = read();
build(1, n, 1);
for(ll i = n; i >= 1; i--){
p[i] = query(s[i] + 1, 1, n, 1);
remove(p[i], 1, n, 1);
}
for(ll i = 1; i < n; i++)
printf("%lld ", p[i]);
printf("%lld\n", p[n]);
return 0;
}
数列编辑器
的确是平衡树板子题,但是这里不讲平衡树。
考虑维护分别对光标前的数和光标后的数维护树状数组,那么事情就变得简单多了。
假设光标前树状数组为
插入:在
删除:在
左移:把
右移:同理。
查询:分三种情况,全在
修改:判断在哪棵树上改哪棵即可。
std:
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 3e5 + 10;
int n;
struct Tree{
int id, c[N];
inline void add(int x, int y){
for(; x <= n; x += x & (-x)) c[x] += y;
}
inline void del(){
add(id, qry(id - 1) - qry(id)), id--;
}
inline int qry(int x){
int res = 0;
for(; x; x -= x & (-x)) res += c[x];
return res;
}
}t1, t2;
char op[5];
signed main(){
#ifndef ONLINE_JUDGE
freopen("test.in", "r", stdin);
freopen("test.out", "w", stdout);
#endif
ios :: sync_with_stdio(false);
cin >> n;
for(int i = 1; i <= n; ++i){
cin >> op;
if(op[0] == 'I'){
int x; cin >> x;
t1.add(++t1.id, x);
}else if(op[0] == 'D') t1.del();
else if(op[0] == 'L'){
if(t1.id == 0) continue;
int v = t1.qry(t1.id) - t1.qry(t1.id - 1);
t1.del(), t2.add(++t2.id, v);
}else if(op[0] == 'R'){
if(t2.id == 0) continue;
int v = t2.qry(t2.id) - t2.qry(t2.id - 1);
t2.del(), t1.add(++t1.id, v);
}else if(op[0] == 'Q'){
int l, r; cin >> l >> r;
if(t1.id >= r) cout << t1.qry(r) - t1.qry(l - 1) << endl;
else if(t1.id < l) cout << t2.qry(t2.id - (l - t1.id) + 1) - t2.qry(t2.id - (r - t1.id)) << endl;
else cout << (t1.qry(t1.id) - t1.qry(l - 1)) + (t2.qry(t2.id) - t2.qry(t2.id - (r - t1.id))) << endl;
}else{
int p, v; cin >> p >> v;
if(t1.id >= p) t1.add(p, v - (t1.qry(p) - t1.qry(p - 1)));
else{
p = t2.id - (p - t1.id) + 1;
t2.add(p, v - (t2.qry(p) - t2.qry(p - 1)));
}
}
}
return 0;
}