解题思路:
- 首先我们知道交换两个数
a
[
l
]
和
a
[
r
]
a[l]和a[r]
a[l]和a[r]影响到的区间是
[
l
+
1
,
r
−
1
]
[l+1,r-1]
[l+1,r−1]
- 对于
a
[
l
]
a[l]
a[l],我们要减去
[
l
+
1
,
r
−
1
]
[l+1,r-1]
[l+1,r−1]里面比
a
[
l
]
a[l]
a[l]大的,加上比
a
[
l
]
a[l]
a[l]小的。
- 对于
a
[
r
]
a[r]
a[r]同理反过来就好了。
- 如果
a
[
l
]
>
a
[
r
]
:
a
n
s
+
+
a[l]>a[r]:ans++
a[l]>a[r]:ans++
- 如果
a
[
r
]
>
a
[
l
]
:
a
n
s
−
−
a[r]>a[l]:ans--
a[r]>a[l]:ans−−
- 那么我们就要有个数据结构去查询任意区间里面比
a
[
l
o
r
r
]
a[l\;or\;r]
a[lorr]大或者小的数?
→
\rightarrow
→权值线段树
- 但是
权
值
线
段
树
叶
子
节
点
只
能
维
护
值
域
权值线段树叶子节点只能维护值域
权值线段树叶子节点只能维护值域,对于任意区间怎么办?
- 就是我们可以用前缀和的思想
[
l
,
r
]
=
[
1
,
r
]
−
[
1
,
l
−
1
]
[l,r]=[1,r]-[1,l-1]
[l,r]=[1,r]−[1,l−1]
- 假设区间是
[
1
,
n
]
[1,n]
[1,n],那么我们可以开
n
n
n个权值线段树,第
i
i
i个权值线段树维护的是
[
1
,
i
]
[1,i]
[1,i]里面的数?
- 但是我们要交换
a
[
l
]
和
a
[
r
]
a[l]和a[r]
a[l]和a[r]那么是不是要修改
[
l
,
n
]
[l,n]
[l,n]和
[
r
,
n
]
[r,n]
[r,n]里面所有的线段树?这里就是典型的一个位置修改影响后面n个区间
- 时间复杂度肯定吃不下!!
- 我们可以用树状数组求前缀和的思想:对于单点的贡献我们只修改后面的
l
o
g
log
log个位置。查询的时候把
l
o
g
log
log位置信息叠加就可以了
- 那么树状数组套线段树就产生了!!
AC code
#include <bits/stdc++.h>
#define mid ((l + r) >> 1)
#define Lson rt << 1, l , mid
#define Rson rt << 1|1, mid + 1, r
#define ms(a,al) memset(a,al,sizeof(a))
#define log2(a) log(a)/log(2)
#define lowbit(x) ((-x) & x)
#define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define INF 0x3f3f3f3f
#define LLF 0x3f3f3f3f3f3f3f3f
#define f first
#define s second
#define endl '\n'
using namespace std;
const int N = 2e6 + 10, mod = 1e9 + 9;
const int maxn = 500010;
const long double eps = 1e-5;
const int EPS = 500 * 500;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PII;
typedef pair<ll,ll> PLL;
typedef pair<double,double> PDD;
template<typename T> void read(T &x) {
x = 0;char ch = getchar();ll f = 1;
while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}
while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}
template<typename T, typename... Args> void read(T &first, Args& ... args) {
read(first);
read(args...);
}
vector<int> lis;
int n;
int arr[maxn];
struct Segtree {
int lson, rson, val;
}tr[maxn * 10];
int root[maxn], cnt;
inline void pushup(int rt) {
tr[rt].val = tr[tr[rt].lson].val + tr[tr[rt].rson].val;
}
inline void update(int &rt, int l, int r, int pos, int val) {
if(!rt) rt = ++ cnt;
if(l == r) {
tr[rt].val += val;
return;
}
if(pos <= mid) update(tr[rt].lson,l,mid,pos,val);
else update(tr[rt].rson,mid+1,r,pos,val);
pushup(rt);
}
inline int getans(int rt, int l, int r, int posl, int posr) {
if(!rt || !posr) return 0;
if(l >= posl && r <= posr) return tr[rt].val;
int ans = 0;
if(posl <= mid) ans += getans(tr[rt].lson,l,mid,posl,posr);
if(posr > mid) ans += getans(tr[rt].rson,mid+1,r,posl,posr);
return ans;
}
inline void add(int x,int pos, int val) {
while(x < n) {
update(root[x],1,n,pos,val);
x += lowbit(x);
}
}
inline int asklow(int pos, int val) {
int ans = 0;
while(pos) {
ans += getans(root[pos],1,n,1,val-1);
pos -= lowbit(pos);
}
return ans;
}
inline int askup(int pos, int val) {
int ans = 0;
while(pos) {
ans += getans(root[pos],1,n,val+1,n);
pos -= lowbit(pos);
}
return ans;
}
inline int getid(int x) {
return lower_bound(lis.begin(),lis.end(),x) - lis.begin() + 1;
}
int main() {
IOS;
cin >> n;
for(int i = 1; i <= n; ++ i) {
cin >> arr[i];
lis.push_back(arr[i]);
}
sort(lis.begin(),lis.end());
lis.erase(unique(lis.begin(),lis.end()),lis.end());
for(int i = 1; i <= n; ++ i) arr[i] = getid(arr[i]);
ll ans = 0;
for(int i = 1; i <= n; ++ i) {
ans += askup(i-1,arr[i]);
add(i,arr[i],1);
}
cout << ans << endl;
int q;
cin >> q;
while(q--) {
int l, r;
cin >> l >> r;
if(l > r) swap(l,r);
ans -= asklow(r-1,arr[l]) - asklow(l,arr[l]);
ans -= askup(r-1,arr[r]) - askup(l,arr[r]);
ans += asklow(r-1,arr[r]) - asklow(l,arr[r]);
ans += askup(r-1,arr[l]) - askup(l,arr[l]);
if(arr[l] > arr[r]) ans --;
if(arr[l] < arr[r]) ans ++;
add(l,arr[l],-1);
add(r,arr[r],-1);
swap(arr[l],arr[r]);
add(l,arr[l],1);
add(r,arr[r],1);
cout << ans << endl;
}
return 0;
}