zoukankan      html  css  js  c++  java
  • [CF785E]Anton and Permutation

    题目大意:有一串数为$1sim n(nleqslant2 imes10^5)$,$m(mleqslant5 imes10^4)$次询问,每次问交换位置为$l,r$的两个数后数列中逆序对的个数。

    题解:发现交换位置为$l,r$的数后,逆序对的变化只和区间$(l,r)$内的数与$s_l,s_r$的大小关系有关,设$S_i$表示区间$(l,r)$中比$s_i$小的数,$B_i$表示区间$(l,r)$中比$s_i$大的数,$ans'=ans+S_r-B_r-S_l+B_l$。设$len=r-l-1$,$ans'=ans+S_r-(len-S_r)-S_l+(len-S_l)=ans+2(S_r-S_l)$。

    考虑分块,设块大小为$S$,在块内排序,在边角处暴力,在整块处二分查找位置,询问的复杂度是$O(2S+dfrac n Slog_2S)$;修改为二分处位置直接插入或删除,复杂度$O(4S)$,所以当$S$略大于$sqrt n$时最优。(反正我懒得算,随便猜一个)

    卡点:

      1. 计算$2(S_r-S_l)$时使用了位运算,当$S_r-S_l$为负数时出锅
      2. 最开始块大小设成了$512$,计算块时用了$2^8$

    C++ Code:

    #include <algorithm>
    #include <cstdio>
    #include <vector>
    #define maxn 200010
    const int BSZ = 1000, BNUM = maxn / BSZ + 10;
    
    int n, m;
    long long ans;
    int L[BNUM], R[BNUM], bel[maxn], s[maxn];
    std::vector<int> V[BNUM];
    
    int query(int l, int r, int x) {
    	if (l > r) return 0;
    	const int lb = bel[l], rb = bel[r];
    	int res = 0;
    	if (lb == rb) for (int i = l; i <= r; ++i) res += s[i] < x;
    	else {
    		for (int i = l; i <= R[lb]; ++i) res += s[i] < x;
    		for (int i = lb + 1; i < rb; ++i) res += std::upper_bound(V[i].begin(), V[i].end(), x) - V[i].begin();
    		for (int i = L[rb]; i <= r; ++i) res += s[i] < x;
    	}
    	return res;
    }
    
    int main() {
    	scanf("%d%d", &n, &m);
    	for (int i = 1; i <= n; ++i) V[bel[i] = i / BSZ + 1].push_back(s[i] = i);
    	const int B = bel[n];
    	for (int i = 1; i <= B; ++i) {
    		L[i] = (i - 1) * BSZ;
    		R[i] = L[i] + BSZ - 1;
    	}
    	L[1] = 1, R[B] = n;
    	while (m --> 0) {
    		int l, r;
    		scanf("%d%d", &l, &r);
    		if (l == r) {
    			printf("%lld
    ", ans);
    			continue;
    		}
    		if (l > r) std::swap(l, r);
    		const int lb = bel[l], rb = bel[r];
    
    		ans += (query(l + 1, r - 1, s[r]) - query(l + 1, r - 1, s[l])) * 2;
    		ans += (s[l] < s[r]) ? 1 : -1;
    		printf("%lld
    ", ans);
    
    		if (lb != rb) {
    			V[lb].erase(std::lower_bound(V[lb].begin(), V[lb].end(), s[l]));
    			V[lb].insert(std::upper_bound(V[lb].begin(), V[lb].end(), s[r]), s[r]);
    			V[rb].erase(std::lower_bound(V[rb].begin(), V[rb].end(), s[r]));
    			V[rb].insert(std::upper_bound(V[rb].begin(), V[rb].end(), s[l]), s[l]);
    		}
    		std::swap(s[l], s[r]);
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    开源软件
    delphi 语法 点滴总结clientdataset
    combobox 下拉框 高度 调节 呵呵
    Delphi7中ClientDataSet的排序
    clientdataset 修改记录 成功
    http://bbs.csdn.net/topics/340046630 dbgrid怎么获取当前记录值
    Delphi中StrToDateTime函数TFormatSettings参数的使用
    IncSecond:将一个TDateTime变量加减一定数量的秒数
    clientdataset 做为 单机数据库的 使用 学习
    cmake命令用法整理list命令
  • 原文地址:https://www.cnblogs.com/Memory-of-winter/p/10329505.html
Copyright © 2011-2022 走看看