動態逆序對(刪除數)--洛谷P1393(離散化+分塊+樹狀數組)&洛谷P3157

題目鏈接https://www.luogu.org/problem/P1393

題目描述

對於給定的一段正整數序列,我們定義它的逆序對的個數爲序列中ai>aj且i<j的有序對(i,j)的個數。你需要計算出一個序列的逆序對組數及其刪去其中的某個數的逆序對組數。

輸入格式

第一行,兩個數n,m,表示序列中有n個數,要刪去m個數

第二行n個數,表示給定的序列。

第三行m個數,第i個數di表示要刪去原序列中的第di個數。

輸出格式

一行m+1個數。第一個數表示給定序列的逆序對組數,第i+1個數表示刪去第di個數後序列的逆序對組數(刪去的數不再恢復)

輸入輸出樣例

輸入 

6 3
5 4 2 6 3 1
2 1 4

輸出

11 7 4 2

說明/提示

對於20%的數據,n≤2500

對於另30%的數據,m=0

對於100%的數據,n≤40000,m≤n/2,且保證第二行n個數互不相同,第三行m個數互不相同。


這題題目有點問題,它的a[i]的範圍沒給你,導致了一發RE。。。所以我們需要對a[i]離散化,又由於他的a[i]是相互不同的,那麼我們sort完之後用unordered_map離散化就好了:

for (int i=1; i<=n; i++) {
	in(a[i].val);//快讀
	b[i]=a[i];
}
sort(b+1,b+1+n,cmp);
for (int i=1; i<=n; i++) q[b[i].val]=i;

接下來就是暴力分塊了,首先我們要清楚的是,刪去了這個數之後,他會的逆序對貢獻會減少前面比他大的數的個數,再減少後面比他小的數的個數,比如5 4 3 2 1  我們刪去了3,那麼前面比他大的數的個數,也就是2(5和4比他大),後面比他小的數的個數爲2(2和1)

所以我們就直接對每個塊排序,對於包含位置x的塊直接暴力數:

if (loca==i){
	for (int j=L[i]; j<=R[i]; j++) {
		if (a[j].pos==pos) {
			a[j].val=inf;
			continue;
		}
		if ((a[j].pos<pos && a[j].val>val) || (a[j].pos>pos && a[j].val<val)) ans--;
	}
	sort(a+L[i],a+R[i]+1,cmp);
	R[i]--;//這個塊中元素刪去了一個,縮小塊
}

對於loca前面的塊,我們找有多少個比他大的數的個數,也就是二分查找:

if (i<loca) {
	int nb=R[i]-L[i]+1;
	int it=nb-(lower_bound(a+L[i],a+R[i]+1,node {pos,val})-(a+L[i]));
	ans-=it;
}

後面的塊也是一樣的。

當然,我們對我們需要對塊進行初始化,先排好序就好了

以下是AC代碼:

#include <bits/stdc++.h>
using namespace std;

const int mac=1e5+10;
const int inf=1e9+10;

#define ll long long

int L[1000],R[1000],id[mac];
int tree[mac],mp[mac],t,n;
ll ans=0;
struct node
{
    int pos,val;
    bool operator<(const node &a)const{
        return val<a.val;
    }
}a[mac],b[mac];

int lowbit(int x){return x&-x;}

int query(int pos)
{
    int sum=0;
    while (pos){
        sum+=tree[pos];
        pos-=lowbit(pos);
    }
    return sum;
}

void update(int pos,int val)
{
    while (pos<=n){
        tree[pos]+=val;
        pos+=lowbit(pos);
    }
}

bool cmp(node a,node b){return a.val<b.val;}
bool cmp2(const node &a,const node &b) {return a.val<b.val;}

void solve(int pos,int val)
{
    int loca=id[pos];
    for (int i=1; i<=t; i++){
    	if (L[i]>R[i]) continue;
        if (i<loca){
            int nb=R[i]-L[i]+1;
            int it=nb-(lower_bound(a+L[i],a+R[i]+1,node{pos,val})-(a+L[i]));
            ans-=it;
        }
        else if (i>loca){
            int it=lower_bound(a+L[i],a+R[i]+1,node{pos,val})-(a+L[i]);
            ans-=it;
        }
        else{
            for (int j=L[i]; j<=R[i]; j++){
                if (a[j].pos==pos){a[j].val=inf;continue;}
                if ((a[j].pos<pos && a[j].val>val) || (a[j].pos>pos && a[j].val<val)) ans--;
            }
            sort(a+L[i],a+R[i]+1,cmp);
            R[i]--;
        }
    }
}

void in(int &x)
{
	int f=0;
	char ch=getchar();
	while (ch>'9' || ch<'0') ch=getchar();
	while (ch<='9' && ch>='0') f=(f<<3)+(f<<1)+ch-'0',ch=getchar();
	x=f;
}

void out(ll x)
{
	if (x>=10)
		out(x/10);
	putchar(x%10+'0');
}

unordered_map<int,int>q;

int main()
{
    //freopen("in.txt","r",stdin);
	int m;
    in(n);in(m);
    t=sqrt(n);
    for (int i=1; i<=t; i++){
        L[i]=(i-1)*t+1;
        R[i]=i*t;
    }
    if (R[t]<n) t++,L[t]=R[t-1]+1,R[t]=n;
    for (int  i=1; i<=t; i++)
        for (int j=L[i]; j<=R[i]; j++)
            id[j]=i;
    ans=0;
    for (int i=1; i<=n; i++){
        in(a[i].val);
        b[i]=a[i];
    }
    sort(b+1,b+1+n,cmp);
    for (int i=1; i<=n; i++) q[b[i].val]=i;
    for (int i=1; i<=n; i++) {
        mp[i]=q[a[i].val];a[i].pos=i;
        ans+=i-1-query(q[a[i].val]);
        update(q[a[i].val],1);
    }
    for (int i=1; i<=t; i++){
        sort(a+L[i],a+R[i]+1,cmp);
        for (int j=L[i]; j<=R[i]; j++) a[j].val=q[a[j].val];
    }
    out(ans);
    for (int i=1; i<=m; i++){
        int x;
        in(x);
        solve(x,mp[x]);	
        putchar(' ');
        out(ans);
    }
    putchar('\n');
    return 0;
}

還有一題類似的,洛谷P3157,這題的數據比較毒瘤,要開O2優化(可以手動開O2)才能過

題目鏈接https://www.luogu.org/problem/P3157

方法和上面是一樣的,刪去離散化就可以了:

#pragma GCC optimize(3)
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#pragma GCC optimize("-fgcse")
#pragma GCC optimize("-fgcse-lm")
#pragma GCC optimize("-fipa-sra")
#pragma GCC optimize("-ftree-pre")
#pragma GCC optimize("-ftree-vrp")
#pragma GCC optimize("-fpeephole2")
#pragma GCC optimize("-ffast-math")
#pragma GCC optimize("-fsched-spec")
#pragma GCC optimize("unroll-loops")
#pragma GCC optimize("-falign-jumps")
#pragma GCC optimize("-falign-loops")
#pragma GCC optimize("-falign-labels")
#pragma GCC optimize("-fdevirtualize")
#pragma GCC optimize("-fcaller-saves")
#pragma GCC optimize("-fcrossjumping")
#pragma GCC optimize("-fthread-jumps")
#pragma GCC optimize("-funroll-loops")
#pragma GCC optimize("-fwhole-program")
#pragma GCC optimize("-freorder-blocks")
#pragma GCC optimize("-fschedule-insns")
#pragma GCC optimize("inline-functions")
#pragma GCC optimize("-ftree-tail-merge")
#pragma GCC optimize("-fschedule-insns2")
#pragma GCC optimize("-fstrict-aliasing")
#pragma GCC optimize("-fstrict-overflow")
#pragma GCC optimize("-falign-functions")
#pragma GCC optimize("-fcse-skip-blocks")
#pragma GCC optimize("-fcse-follow-jumps")
#pragma GCC optimize("-fsched-interblock")
#pragma GCC optimize("-fpartial-inlining")
#pragma GCC optimize("no-stack-protector")
#pragma GCC optimize("-freorder-functions")
#pragma GCC optimize("-findirect-inlining")
#pragma GCC optimize("-fhoist-adjacent-loads")
#pragma GCC optimize("-frerun-cse-after-loop")
#pragma GCC optimize("inline-small-functions")
#pragma GCC optimize("-finline-small-functions")
#pragma GCC optimize("-ftree-switch-conversion")
#pragma GCC optimize("-foptimize-sibling-calls")
#pragma GCC optimize("-fexpensive-optimizations")
#pragma GCC optimize("-funsafe-loop-optimizations")
#pragma GCC optimize("inline-functions-called-once")
#pragma GCC optimize("-fdelete-null-pointer-checks")
#include <bits/stdc++.h>
using namespace std;

const int mac=1e5+10;
const int inf=1e9+10;

#define ll long long

int L[1000],R[1000],id[mac];
int tree[mac],mp[mac],t,n;
ll ans=0;
struct node
{
    int pos,val;
    bool operator<(const node &a)const{
        return val<a.val;
    }
}a[mac];

int lowbit(int x){return x&-x;}

int query(int pos)
{
    int sum=0;
    while (pos){
        sum+=tree[pos];
        pos-=lowbit(pos);
    }
    return sum;
}

void update(int pos,int val)
{
    while (pos<=n){
        tree[pos]+=val;
        pos+=lowbit(pos);
    }
}

bool cmp(node a,node b){return a.val<b.val;}
bool cmp2(const node &a,const node &b) {return a.val<b.val;}

void solve(int pos,int val)
{
    int loca=id[pos];
    for (int i=1; i<=t; i++){
    	if (L[i]>R[i]) continue;
        if (i<loca){
            int nb=R[i]-L[i]+1;
            int it=nb-(lower_bound(a+L[i],a+R[i]+1,node{pos,val})-(a+L[i]));
            ans-=it;
        }
        else if (i>loca){
            int it=lower_bound(a+L[i],a+R[i]+1,node{pos,val})-(a+L[i]);
            ans-=it;
        }
        else{
            for (int j=L[i]; j<=R[i]; j++){
                if (a[j].pos==pos){a[j].val=inf;continue;}
                if ((a[j].pos<pos && a[j].val>val) || (a[j].pos>pos && a[j].val<val)) ans--;
            }
            sort(a+L[i],a+R[i]+1,cmp);
            R[i]--;
        }
    }
}

void in(int &x)
{
	int f=0;
	char ch=getchar();
	while (ch>'9' || ch<'0') ch=getchar();
	while (ch<='9' && ch>='0') f=(f<<3)+(f<<1)+ch-'0',ch=getchar();
	x=f;
}

void out(ll x)
{
	if (x>=10)
		out(x/10);
	putchar(x%10+'0');
}

int main()
{
    //freopen("in.txt","r",stdin);
	int m;
    in(n);in(m);
    t=sqrt(n);
    for (int i=1; i<=t; i++){
        L[i]=(i-1)*t+1;
        R[i]=i*t;
    }
    if (R[t]<n) t++,L[t]=R[t-1]+1,R[t]=n;
    for (int  i=1; i<=t; i++)
        for (int j=L[i]; j<=R[i]; j++)
            id[j]=i;
    ans=0;
    for (int i=1; i<=n; i++){
        in(a[i].val);
        mp[a[i].val]=i;a[i].pos=i;
        ans+=i-1-query(a[i].val);
        update(a[i].val,1);
    }
    for (int i=1; i<=t; i++)
        sort(a+L[i],a+R[i]+1,cmp);
    for (int i=1; i<=m; i++){
        int x;
        in(x);
        out(ans);
        putchar('\n');
        solve(mp[x],x);		
    }
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章