Brief description:
给定一个数组,你必须交换其中的两个数,最小化逆序对数。。
Analysis:
题目来源:http://www.ioi-jp.org/joi/2012/2013-ho/
问题 5:http://www.ioi-jp.org/joi/2012/2013-ho/2013-ho-t5-review.pdf
离线 + 线段树。
要点是数形结合。。一图流:
。。。交换两个数(前者比后者大)所获得的收益。。是 2*矩形中的面积)+ 1*边界的面积 + 1。。。(先不考虑边界)。。
问题现在便转化为检查这些极大子矩形。。。
什么是极大子矩形呢?再来一张图:
极大子矩形一定是某个赤点和右下角的某个青点所组成的图形。。。
于是我们将点集(事件)分成三类。。赤点和蓝点都单调递增。。因此从左到右扫描线。、、记录每个事件离散化后的纵坐标。。
- 赤点(左上角):。。。在线段树中激活这个坐标。。
- 黑点(其他):。。加入这个事件。。将线段树中这个点坐标到最近激活赤点 += 2.。。
- 青点(右下角):。。。弹出所有纵坐标小于它的黑点(优先队列维护)。。区间求最值。。。
只需要区间加减,区间求最值。。线段树即可。。。
最后还要讨论各种边界的情况。。。
假设所有数都一样。。返回 0 。。。否则求出初始的逆序对 init_ans。。如果存在两个数相等。那么初始答案是 init_ans。。否则是 init_ans – 1。。
再讨论矩形的边界问题:
对于上边界:
。。当插入一个黑点时。。实际和这个黑点相等的那个坐标只能 += 1。。。
对于下边界:
。。当出现青点时。不仅要弹出所有小于它的黑点。。还要【消弱】等于它的黑点 -= 1。。。
//}/* .................................................................................................................................. */
const int N = int(1e5) + 9;
int a[N]; VI P; bool red[N], blue[N];
int n;
namespace ST{
#define lx (x<<1)
#define rx (lx|1)
#define ml (l+r>>1)
#define mr (ml+1)
#define lc lx, l, ml
#define rc rx, mr, r
#define rt 1, 1, P.size()
int T[4*N], D[4*N], a, b, d, ll, rr;
void upd(int x){
T[x] = max(T[lx], T[rx]);
}
void inc(int x, int d){
D[x] += d;
T[x] += d;
}
void rls(int x){
if (D[x]){
inc(lx, D[x]), inc(rx, D[x]);
D[x] = 0;
}
}
void add(int x, int l, int r){
if (b < l || r < a) return;
if (a <= l && r <= b){
inc(x, d);
}
else{
rls(x);
add(lc); add(rc);
upd(x);
}
}
void Add(int _a, int _b, int _d){
a = _a, b = _b, d = _d; add(rt);
}
int query(int x, int l, int r){
if (b < l || r < a) return 0;
if (a <= l && r <= b){
return T[x];
}
else{
rls(x);
return max(query(lc), query(rc));
}
}
int query(){
a = ll+1, b = rr; int z = a <= b ? query(rt) : 0; ++z;
return z;
}
}
namespace BIT{
int C[N], n;
int Sum(int x){
int z=0; for (;x;x^=low_bit(x)) z += C[x];
return z;
}
void Add(int x, int d){
for(;x<=n;x+=low_bit(x)) C[x] += d;
}
int Sum(int l, int r){
return Sum(r) - Sum(l-1);
}
} //using namespace BIT;
struct black{
int l, r;
black(int _l, int _r):l(_l),r(_r){
}
bool operator <(const black& rhs) const{
return l < rhs.l;
}
bool operator >(const black& rhs) const{
return l > rhs.l;
}
void add() const{
ST::Add(l, r, 2);
ST::Add(l, l, -1);
}
void del() const{
ST::Add(l, r, -2);
}
void weak() const{
ST::Add(l, r, -1);
}
};
priority_queue<black, vector<black>, greater<black> > Q;
int main(){
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
//freopen("out.txt", "w", stdout);
#endif
REP_C(i, RD(n)) P.PB(RD(a[i])); UNQ(P);
BIT::n = P.size();
LL init_ans = 0; bool same = 0, all_same = 1; REP(i, n){
a[i] = LBD(P, a[i])+1;
init_ans += i - BIT::Sum(a[i]);
same |= (BIT::Sum(a[i]) - BIT::Sum(a[i]-1));
all_same &= (!i || a[i] == a[i-1]);
BIT::Add(a[i], 1);
}
if (all_same){
puts("0");
exit(0);
}
LL ans = init_ans + 1; if (same) --ans;
int t = 0; REP(i, n){
red[i] = checkMax(t, a[i]);
}
t = INF; DWN(i, n, 0){
blue[i] = checkMin(t, a[i]);
}
ST::ll = 0, ST::rr = -1;
REP(i, n){
if (red[i]){
ST::rr = a[i];
}
else if (blue[i]){
while (!Q.empty() && Q.top().l < a[i]){
Q.top().del();
Q.pop();
}
vector<black> QQ;
while (!Q.empty() && Q.top().l == a[i]){
Q.top().weak(); QQ.PB(Q.top()); Q.pop();
}
ST::ll = a[i];
checkMin(ans, init_ans - (ST::query()));
ECH(it, QQ) it->weak();
}
else{
black t = black(a[i], ST::rr);
Q.push(t); t.add();
}
}
OT(ans);
}






Alca
Amber
Belleve Invis
Chensiting123
Edward_mj
Fotile96
Hlworld
Kuangbin
Liyaos
Lwins
LYPenny
Mato 完整版
Mikeni2006
Mzry
Nagatsuki
Neko13
Oneplus
Rukata
Seter
Sevenkplus
Sevenzero
Shirleycrow
Vfleaking
wangzhpp
Watashi
WJMZBMR
Wywcgs
XadillaX
Yangzhe
三途川玉子
About.me
Vijos
