BZOJ2141&洛谷1975 排队 【线段树套treap】

题目

排排坐,吃果果,生果甜嗦嗦,大家笑呵呵。你一个,我一个,大的分给你,小的留给我,吃完果果唱支歌,大家乐和和。

红星幼儿园的小朋友们排起了长长地队伍,准备吃果果。不过因为小朋友们的身高有所区别,排成的队伍高低错乱,极不美观。设第i个小朋友的身高为hi,我们定义一个序列的杂乱程度为:满足i<j且hi>hj的(i,j)数量。

幼儿园阿姨每次会选出两个小朋友,交换他们的位置,请你帮忙计算出每次交换后,序列的杂乱程度。为方便幼儿园阿姨统计,在未进行任何交换操作时,你也应该输出该序列的杂乱程度。

输入格式

第一行为一个正整数n,表示小朋友的数量;

第二行包含n个由空格分隔的正整数h1,h2,…,hn,依次表示初始队列中小朋友的身高;

第三行为一个正整数m,表示交换操作的次数;

以下m行每行包含两个正整数ai和bi­,表示交换位置ai与位置bi的小朋友。

输出格式

输出文件共m+1行,第i行一个正整数表示交换操作i结束后,序列的杂乱程度。

输入样例

3
130 150 140
2
2 3
1 3

输出样例

1
0
3

提示

【样例说明】

未进行任何操作时,(2,3)满足条件;

操作1结束后,序列为130 140 150,不存在满足i<j且hi>hj的(i,j)对;

操作2结束后,序列为150 140 130,(1,2),(1,3),(2,3)共3对满足条件的(i,j)。

对于15%的数据,n,m le 15n,m≤15;

对于30%的数据,n,m le 200n,m≤200;

在剩下的70%数据中:

存在15%的数据,h_ih
i
​ 各不相同;

存在15%的数据,1^{10} le h_i le 1^{60}1
10
≤h
i
​ ≤1
60

以上两类数据不存在交集。

对于100%的数据,1 le m le 2 imes 10^31≤m≤2×10
3
,1 le n le 2 imes 10^41≤n≤2×10
4
,1 le h_i le 10^91≤h
i
​ ≤10
9
,a_i e b_ia
i
​ ≠b
i
​ ,1 le a_i,b_i le n1≤a
i
​ ,b
i
​ ≤n。

题解

数据结构什么的查错真的是查得想死啊,,
不过A了就很舒服~~

蒟蒻没写过treap,今天一跃写了线段树套treap,感觉整个人要虚脱

嘴上AC还是不难:
先用离散化 + 树状数组算出初始的逆序对
之后没交换L和R,我们只需要考虑他们对答案带来的影响:
①L和R,若h[L]>h[R],交换后逆序对会减少1;若h[L] < h[R],交换后逆序对会增加1
②L和R与他们两边的元素的相对位置不变,只对(L,R)区间内产生影响,只要求出(L,R)区间内比h[L]和h[R]小和大的个数来更新答案即可

【一开始忘记判l>r WA了,后来发现一开始求逆序对时没考虑相等,又WA 。。QAQ】

#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#define LL long long int
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define BUG(s,n) for (int i = 1; i <= (n); i++) cout<<s[i]<<' '; puts("");
#define lbt(u) (u & -u)
using namespace std;
const int maxn = 20005,maxm = 5000005,INF = 1000000000;
inline int read(){
	int out = 0,flag = 1; char c = getchar();
	while (c < 48 || c > 57) {if (c == '-') flag = -1; c = getchar();}
	while (c >= 48 && c <= 57) {out = (out << 3) + (out << 1) + c - '0'; c = getchar();}
	return out * flag;
}
int n,m,A[maxn],rt[4 * maxn];
int Siz,ls[maxm],rs[maxm],val[maxm],cnt[maxm],siz[maxm],rnd[maxm];
void pup(int u){
	siz[u] = siz[ls[u]] + siz[rs[u]] + cnt[u];
}
void lturn(int& u){
	int t = rs[u]; rs[u] = ls[t]; ls[t] = u;
	pup(u); pup(t); u = t;
}
void rturn(int& u){
	int t = ls[u]; ls[u] = rs[t]; rs[t] = u;
	pup(u); pup(t); u = t;
}
void ins(int& u,int v){
	if (!u) {
		u = ++Siz; val[u] = v;
		rnd[u] = rand(); siz[u] = cnt[u] = 1;
	}
	else if (val[u] > v) {
		siz[u]++; ins(ls[u],v);
		if (rnd[ls[u]] > rnd[u]) rturn(u);
	}
	else if (val[u] < v) {
		siz[u]++; ins(rs[u],v);
		if (rnd[rs[u]] > rnd[u]) lturn(u);
	}
	else cnt[u]++,siz[u]++;
}
void del(int &u,int v)
{
	if(!u) return;
    if(val[u] == v)
    {
        if(cnt[u] > 1) cnt[u]--,siz[u]--;
        else if(ls[u] * rs[u] == 0) u = ls[u] + rs[u];
        else if(rnd[ls[u]] > rnd[rs[u]]) rturn(u),del(u,v);
        else lturn(u),del(u,v);
    }
    else if(v < val[u]) siz[u]--,del(ls[u],v);
    else siz[u]--,del(rs[u],v);
}
int getpre(int r,int v){
	int ans = 0,u = rt[r];
	while (true){
		if (!u) return ans;
		else if (val[u] > v) u = ls[u];
		else if (val[u] < v) ans += siz[ls[u]] + cnt[u],u = rs[u];
		else return ans + siz[ls[u]];
	}
}
int getpost(int r,int v){
	int ans = 0,u = rt[r];
	while (true){
		if (!u) return ans;
		else if (val[u] < v) u = rs[u];
		else if (val[u] > v) ans += siz[rs[u]] + cnt[u],u = ls[u];
		else return ans + siz[rs[u]];
	}
}
void build(int u,int l,int r){
	for (int i = l; i <= r; i++) ins(rt[u],A[i]);
	if (l == r) return;
	int mid = l + r >> 1;
	build(u << 1,l,mid);
	build(u << 1 | 1,mid + 1,r);
}
void modify(int u,int l,int r,int pos,int v){
	del(rt[u],A[pos]); ins(rt[u],v);
	if (l == r) return;
	int mid = l + r >> 1;
	if (mid >= pos) modify(u << 1,l,mid,pos,v);
	else modify(u << 1 | 1,mid + 1,r,pos,v);
}
int Getpre(int u,int l,int r,int L,int R,int v){
	if (l >= L && r <= R) return getpre(u,v);
	int mid = l + r >> 1;
	if (mid >= R) return Getpre(u << 1,l,mid,L,R,v);
	else if (mid < L) return Getpre(u << 1 | 1,mid + 1,r,L,R,v);
	else return Getpre(u << 1,l,mid,L,R,v) + Getpre(u << 1 | 1,mid + 1,r,L,R,v);
}
int Getpost(int u,int l,int r,int L,int R,int v){
	if (l >= L && r <= R) return getpost(u,v);
	int mid = l + r >> 1;
	if (mid >= R) return Getpost(u << 1,l,mid,L,R,v);
	else if (mid < L) return Getpost(u << 1 | 1,mid + 1,r,L,R,v);
	else return Getpost(u << 1,l,mid,L,R,v) + Getpost(u << 1 | 1,mid + 1,r,L,R,v);
}
int b[maxn],s[maxn],Ans;
void add(int u){while (u <= n) s[u] ++,u += lbt(u);}
int query(int u){int tot = 0; while (u) tot += s[u],u -= lbt(u); return tot;}
int getn(int x){return lower_bound(b + 1,b + 1 + n,x) - b;}
int main(){
	n = read(); int l,r;
	REP(i,n) b[i] = A[i] = read();
	sort(b + 1,b + 1 + n);
	for (int i = n; i; i--){
		int t = getn(A[i]);
		Ans += query(t - 1);
		add(t);
	}
	printf("%d
",Ans);
	build(1,1,n);
	m = read();
	while (m--){
		l = read(); r = read();
		if (l > r) swap(l,r);
		if (l == r) {printf("%d
",Ans); continue;}
		if (A[l] < A[r]) Ans++;
		if (A[l] > A[r]) Ans--;
		if (l < r - 1){
			Ans -= Getpre(1,1,n,l + 1,r - 1,A[l]);
			Ans += Getpost(1,1,n,l + 1,r - 1,A[l]);
			Ans -= Getpost(1,1,n,l + 1,r - 1,A[r]);
			Ans += Getpre(1,1,n,l + 1,r - 1,A[r]);
		}
		modify(1,1,n,l,A[r]); modify(1,1,n,r,A[l]);
		swap(A[l],A[r]);
		printf("%d
",Ans);
	}
	return 0;
}

原文地址:https://www.cnblogs.com/Mychael/p/8324471.html