• P1975 [国家集训队]排队 线段树套平衡树维护动态逆序对查询


    $ color{#0066ff}{ 题目描述 }$

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

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

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

    (color{#0066ff}{输入格式})

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

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

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

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

    (color{#0066ff}{输出格式})

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

    (color{#0066ff}{输入样例})

    3
    130 150 140
    2
    2 3
    1 3
    

    (color{#0066ff}{输出样例})

    1
    0
    3
    

    (color{#0066ff}{数据范围与提示})

    【样例说明】

    未进行任何操作时,(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 15)

    对于30%的数据,(n,m le 200)

    在剩下的70%数据中:

    存在15%的数据,(h_i)各不相同;

    存在15%的数据,(1^{10} le h_i le 1^{60})

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

    对于100%的数据,(1 le m le 2 imes 10^3)(1 le n le 2 imes 10^4)(1 le h_i le 10^9)(a_i e b_i)(1 le a_i,b_i le n)

    (color{#0066ff}{题解})

    一句话题意,给你一个序列,每次交换其中两个元素,每次输出逆序对数量

    直接树套树, 每次减去改之前的贡献,然后修改,然后再加上改之后的贡献即可

    #include<bits/stdc++.h>
    #define LL long long
    LL read() {
    	char ch; LL x = 0, f = 1;
    	while(!isdigit(ch = getchar()))(ch == '-') && (f = -f);
    	for(x = ch ^ 48; isdigit(ch = getchar()); x = (x << 1) + (x << 3) + (ch ^ 48));
    	return x * f;
    }
    template<class T> bool chkmax(T &a, const T &b) { return a < b? a = b, 1 : 0; }
    template<class T> bool chkmin(T &a, const T &b) { return b < a? a = b, 1 : 0; }
    const int maxn = 1e5 + 10;
    struct Splay {
    protected:
    	struct node {
    		node *ch[2], *fa;
    		int siz, val;
    		node(int siz = 0, int val = 0): siz(siz), val(val) { ch[0] = ch[1] = fa = NULL; }
    		bool isr() { return this == fa->ch[1]; }
    		void upd() { siz = (ch[0]? ch[0]->siz : 0) + (ch[1]? ch[1]->siz : 0) + 1; }
    		int rkmin() { return (ch[0]? ch[0]->siz + 1 : 1); }
    		int rkmax() { return (ch[1]? ch[1]->siz + 1 : 1); }
    	}*root;
    	void rot(node *x) {
    		node *y = x->fa, *z = y->fa;
    		bool k = x->isr(); node *w = x->ch[!k];
    		if(y != root) z->ch[y->isr()] = x;
    		else root = x;
    		(x->ch[!k] = y)->ch[k] = w;
    		(y->fa = x)->fa = z;
    		if(w) w->fa = y;
    		y->upd(), x->upd();
    	}
    	void splay(node *o) {
    		while(o != root) {
    			if(o->fa != root) rot(o->isr() ^ o->fa->isr()? o : o->fa);
    			rot(o);
    		}
    	}
    	node *merge(node *fa, node *x, node *y) {
    		if(x) x->fa = fa;
    		if(y) y->fa = fa;
    		if(!x || !y) return x? x : y;
    		if(rand() & 1) return x->ch[1] = merge(x, x->ch[1], y), x->upd(), x;
    		else return y->ch[0] = merge(y, x, y->ch[0]), y->upd(), y;
    	}
    public:
    	Splay() { root = NULL; }
    	int querymin(int val) {
    		int rank = 0; node *o = root;
    		while(o) {
    			if(o->val < val) rank += o->rkmin(), o = o->ch[1];
    			else o = o->ch[0];
    		}
    		return rank;
    	}
    	int querymax(int val) {
    		int rank = 0; node *o = root;
    		while(o) {
    			if(o->val > val) rank += o->rkmax(), o = o->ch[0];
    			else o = o->ch[1];
    		}
    		return rank;
    	}
    	void ins(int val) {
    		if(!root) return (void)(root = new node(1, val));
    		node *o = root, *fa = NULL;
    		while(o) fa = o, o = o->ch[val > o->val];
    		fa->ch[val > fa->val] = o = new node(1, val);
    		o->fa = fa, splay(o);
    	}
    	void del(int val) {
    		node *o = root;
    		while(o->val != val)  o = o->ch[val > o->val];
    		splay(o);
    		root = merge(NULL, o->ch[0], o->ch[1]);
    	}
    };
    struct Tree {
    protected:
    	struct node {
    		node *ch[2];
    		int l, r;
    		Splay T;
    		node(int l = 0, int r = 0): l(l), r(r) { ch[0] = ch[1] = NULL; }
    		int mid() { return (l + r) >> 1; }
    	}*root;
    	void build(node *&o, int l, int r, int *a) {
    		o = new node(l, r);
    		for(int i = l; i <= r; i++) o->T.ins(a[i]);
    		if(l == r) return;
    		build(o->ch[0], l, o->mid(), a);
    		build(o->ch[1], o->mid() + 1, r, a);
    	}
    	int querymin(node *o, int l, int r, int val) {
    		if(l > r) return 0;
    		if(l <= o->l && o->r <= r) return o->T.querymin(val);
    		int ans = 0;
    		if(l <= o->mid()) ans += querymin(o->ch[0], l, r, val);
    		if(r > o->mid()) ans += querymin(o->ch[1], l, r, val);
    		return ans;
    	}
    	int querymax(node *o, int l, int r, int val) {
    		if(l > r) return 0;
    		if(l <= o->l && o->r <= r) return o->T.querymax(val);
    		int ans = 0;
    		if(l <= o->mid()) ans += querymax(o->ch[0], l, r, val);
    		if(r > o->mid()) ans += querymax(o->ch[1], l, r, val);
    		return ans;
    	}
    public:
    	void init(int n, int *a) { build(root, 1, n, a); }
    	void change(int pos, int old, int now) {
    		node *o = root; 
    		while(1) {
    			o->T.del(old), o->T.ins(now);
    			if(o->l == o->r) break;
    			if(pos <= o->mid()) o = o->ch[0];
    			else o = o->ch[1];
    		}
    	}
    	int querymin(int l, int r, int val) { return querymin(root, l, r, val); }
    	int querymax(int l, int r, int val) { return querymax(root, l, r, val); }
    }T;
    int val[maxn], n;
    int main() {
    	n = read();
    	for(int i = 1; i <= n; i++) val[i] = read();
    	T.init(n, val);
    	int ans = 0;
    	for(int i = 1; i <= n; i++) ans += T.querymax(1, i - 1, val[i]) + T.querymin(i + 1, n, val[i]);
    	printf("%d
    ", ans >>= 1);
    	for(int Q = read(); Q --> 0;) {
    		int x = read(), y = read();
    		ans -= T.querymax(1, x - 1, val[x]) + T.querymin(x + 1, n, val[x]);
    		T.change(x, val[x], val[y]);
    		ans += T.querymax(1, x - 1, val[y]) + T.querymin(x + 1, n, val[y]);
    		ans -= T.querymax(1, y - 1, val[y]) + T.querymin(y + 1, n, val[y]);
    		T.change(y, val[y], val[x]);
    		ans += T.querymax(1, y - 1, val[x]) + T.querymin(y + 1, n, val[x]);
    		std::swap(val[x], val[y]);
    		printf("%d
    ", ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    可以自己设计和定的报表工具!
    金山词霸取词冲突
    SSRS 2008 Domain User Issue
    第一次用AX2009正式版!
    顶级会议及期刊
    Python基础常识
    Ubuntu系统下查看安装的CUDA和CUDNN的版本
    js内字符串转数组的基本方法
    JavaScript之逻辑分支
    JS入门
  • 原文地址:https://www.cnblogs.com/olinr/p/10656907.html
Copyright © 2020-2023  润新知