[国家集训队]排队
有一个分块做法:
考虑先求出原始序列的答案。
然后考虑交换两个数\(a_l,a_r\)
那么答案的变化区域肯定在\([l,r]\)
于是考虑答案的变化贡献量。
\(i \in [l,r]\)
\(a[i] > a[l],ans + 1\)
\(a[i] < a[l],ans - 1\)
\(a[i] > a[r],ans - 1\)
\(a[i] < a[r],ans + 1\)
那么分块维护就行了。
考虑在块内排序,二分查找就行了。
然后就是更换一下块内的排序数组。
代码鸽了。
找时间把区间众数和这个题的分块做法写了
[国家集训队]排队(直接暴力做法)
#include<bits/stdc++.h>
#define int long long
#define mem(x) memset(x,0,sizeof(x))
using namespace std;
int read(){
int s = 0,w = 1;
char ch = getchar();
while(ch < '0' || ch > '9'){if(ch == '-')w = -1;ch = getchar();}
while(ch >= '0' && ch <= '9')s = s * 10 + ch - '0',ch = getchar();
return s * w;
}
int n,m;
int a[1000010];
int c[1000010],d[1000010];
int cnt;
void merge(int L, int R, int Mid){
int i = L;int j = Mid + 1;int k = L;
while(i <= Mid && j <= R){
if(c[i] <= c[j])d[k ++] = c[i ++];
else{
cnt += Mid - i + 1;
d[k ++] = c[j ++];
}
}
while(i <= Mid)d[k ++] = c[i ++];
while(j <= R)d[k ++] = c[j ++];
for(i = L; i <= R; i ++)c[i] = d[i];
}
void mergesort(int L, int R){
if(L == R)return ;
if(L < R){
int Mid = (L + R) / 2;
mergesort(L, Mid),mergesort(Mid + 1, R);
merge(L, R, Mid);
}
}
signed main(){
cin>>n;
for(int i = 1;i <= n;i ++)a[i] = read(),c[i] = a[i];
mergesort(1,n);
cout<<cnt<<endl;
cin>>m;
while(m --){
int x,y;
x = read(),y = read();
if(x > y)swap(x,y);
if(a[x] > a[y])cnt --;
if(a[y] > a[x])cnt ++;
for(int i = x + 1;i <= y - 1;i ++){
if(a[i] > a[x])cnt ++;
if(a[i] < a[x])cnt --;
if(a[i] < a[y])cnt ++;
if(a[i] > a[y])cnt --;
}
swap(a[x],a[y]);
printf("%lld\n",cnt);
}
return 0;
}