• 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;
    }
    
    
  • 相关阅读:
    SQL 多条件查询
    android实现程序开机自启动
    SendMessage模拟按键所需的虚拟键码
    使用API进行文件读写——CreateFile,ReadFile,WriteFile等
    VB断点拷贝大文件(WIN7系统需要更改某个API函数,具体我也忘了)
    mysql
    webstorm
    ubuntu ftp服务器
    centos ftp 服务器
    nignx
  • 原文地址:https://www.cnblogs.com/Mychael/p/8324471.html
Copyright © 2020-2023  润新知