对于初始排列,就是求原序列的逆序对数。
对于逆序对我们可以拆开来算,用 \([i,j]\) 表示满足 \(a_u =i,a_v=j,i>j\) 二元组 \((u,v)\) 个数。
那么初始答案可以表示为 \(\sum\limits_{i = 1}^{k}\sum\limits_{j = i + 1}^{k}[i,j]\)。
推导之后可以得到,对于一次交换,令交换的两个数为 \(x,y\),我们只用在上一次答案的基础上加上 \(2\times[x,y] - c _x\times c_y\),其中 \(c_i\) 表示 \(i\) 在原序列中出现的次数。
现在我们只用求 \([x,y]\),这个玩意本质上也是求逆序对,考虑根号分治,对于 \(c_x, c_y\le \sqrt n\) 的直接爆算,其余的离线后对整个原序列扫一遍统计答案。
由于 \(q\) 远大于 \(n\) ,我们令 \(lim\) 表示对于 \(c_x, c_y\le lim\) 的 \([x,y]\) 进行爆算,解方程 \(q\times lim = \frac{n^2}{lim}\),解的 \(lim = 100\) 时最优。
/* Author : SharpnessV Right Output ! & Accepted ! */ #include<bits/stdc++.h> //#define int long long #define rep(i, a, b) for(int i = (a);i <= (b);i++) #define pre(i, a, b) for(int i = (a);i >= (b);i--) #define rp(i, a) for(int i = 1; i <= (a); i++) #define pr(i, a) for(int i = (a); i >= 1; i--) #define go(i, x) for(auto i : x) #define mp make_pair #define pb push_back #define pf push_front #define fi first #define se second #define ze(p) memset(p, 0, sizeof(p)) #define mem(p, x) memset(p, x, sizeof(p)) #define YES puts("YES") #define NO puts("NO") #define si(x) (int)(x).size() #define db cerr #define pc putchar #define el putchar('\n') using namespace std; const double eps = 1e-15, pi = 3.1415926535897932385; typedef long long LL; typedef pair<int,int> Pr; const int dx[4] = {1,0,-1,0}, dy[4] = {0,1,0,-1}, inf = 0x7fffffff; //char buf[1<<22],*p1=buf,*p2=buf; //#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++) inline int read(){ int x = 0;bool f = 1;char ch = getchar(); while(!isdigit(ch))f = ('-' == ch ? 0 : 1), ch = getchar(); while(isdigit(ch))x = (x << 1) + (x << 3) + (ch ^ 48), ch = getchar(); if(f)return x;return -x; } inline LL Read(){ LL x = 0;bool f = 1;char ch = getchar(); while(!isdigit(ch))f = ('-' == ch ? 0 : 1), ch = getchar(); while(isdigit(ch))x = (x << 1) + (x << 3) + (ch ^ 48), ch = getchar(); if(f)return x;return -x; } int gcd(int x,int y){return y ? gcd(y, x % y) : x;} int lcm(int x,int y){return x / gcd(x, y) * y;} #define P 1000000007 //#define P 998244353 #define bas 229 inline void ad(int &x, int y){x += y; if(x >= P) x -= P;} inline void su(int &x, int y){x -= y; if(x < 0) x += P;} inline void cmn(int &x,int y){if(y < x) x = y;} inline void cmx(int &x,int y){if(y > x) x = y;} inline void cmn(LL &x, LL y){if(y < x) x = y;} inline void cmx(LL &x, LL y){if(y > x) x = y;} int Pow(int x, int y){ if(y < 0)return Pow(Pow(x, P - 2), -y); int now = 1 ; for(;y;y >>= 1, x = 1LL * x * x % P)if(y & 1) now = 1LL * now * x % P; return now; } #define N 100005 #define M 1000005 int n, m, q, a[N], c[N], u[M], p[N], b[N];LL ans[M], s[N], sum; vector<Pr>e[N];vector<int>f[N]; const int lim = 100; int calc(int x,int y){ int sx = si(f[x]), sy = si(f[y]), cur = 0, j = 1; rp(i, sy){ while(j <= sx && f[x][j - 1] < f[y][i - 1])j++; cur += j - 1; } return cur; } void solve(int x){ memset(s, 0, sizeof(s)); int cnt = 0; rp(i, n){ if(a[i] == x)cnt++; else s[a[i]] += cnt; } go(w, e[x])ans[w.se] = s[w.fi]; } void msort(int l, int r){ if(l == r)return; int mid = (l + r) >> 1; msort(l, mid), msort(mid + 1, r); int top = 0, j = l; rep(i, mid + 1, r){ while(j <= mid && a[j] > a[i])b[++top] = a[j++]; sum += j - l, b[++top] = a[i]; } while(j <= mid)b[++top] = a[j++]; rep(i, l, r)a[i] = b[i - l + 1]; } int main(){ //int T = read();while(T--)solve(); n = read(), m = read(), q = read(); rp(i, n)c[a[i] = read()] ++ , f[a[i]].pb(i); rp(i, m)p[i] = i; rp(i, q){ u[i] = read(); int x = p[u[i]], y = p[u[i] + 1]; swap(p[u[i]], p[u[i] + 1]); if(c[x] < c[y])swap(x, y); if(c[x] > lim)e[x].pb(mp(y, i)); else ans[i] = calc(x, y); } rp(i, m)if(si(e[i]))solve(i); msort(1, n); //cout << "ss " << sum << endl; rp(i, n)p[i] = i; rp(i, q){ int x = p[u[i]], y = p[u[i] + 1]; swap(p[u[i]], p[u[i] + 1]); if(c[x] < c[y])ans[i] = 1LL * c[x] * c[y] - ans[i]; //cout << "Ss " << x << " " << y << " " << ans[i] << " " << c[x] << " " << c[y] << endl; sum += ans[i] * 2 - 1LL * c[x] * c[y]; printf("%lld\n", sum); } return 0; }