1. 程式人生 > >一道線段樹+樹狀陣列的題

一道線段樹+樹狀陣列的題

水上由岐有一個長為n 的序列a1; a2; : : : ; an。接下來她要進行m 次操 作。對於第k 次操作,她會指定jk,然後取出所有i ≥ jk 且ai ≤ ajk 的ai, 將它們從小到大排序後按順序重新放回之前的位置(只有這些數的順序可能改 變,其它數的位置不變)。 定義一個逆序對(i; j) 為滿足i < j 且ai > aj 的一個二元組。第一次操作 前和每次操作結束後,她都想要知道當前序列有多少個逆序對。 任務描述  輸入 第一行,兩個正整數n; m。 第二行,n 個正整數a1; a2; : : : ; an,保證1 ≤ ai ≤ n,可能存在相同值。 第三行,m 個正整數j1; j2; : : : ; jm,保證1 ≤ jk ≤ n。 輸出 第一行,第一個整數表示操作前的逆序對數量,接下來m 個整數表示每次 操作後的逆序對數量。

 樣例資料  輸入 6 2 1 3 4 2 6 1 2 3 輸出 6 3 1 解釋 第一次操作:由1 3 4 2 6 1 變為1 1 4 2 6 3。 第二次操作:由1 1 4 2 6 3 變為1 1 2 3 6 4。  

每次重新排序的數的逆序對數變為0,而其他位置的逆序對數不改變。

所以用樹狀陣列處理出最開始每個位置的逆序對數。(倒著for,每個位置的逆序對數:這個位置以後小於等於它的數。)

然後每次找出需重新排序的數,用線段數找區間最小值,找到後把那個位置對應的值修改為inf.

這樣就再也不會找重複了。

#include<bits/stdc++.h>
using namespace std;
long long  f[800010], zhi[200005];
int n, m,a[200005],b[200005];
void read(long long &x)
{
	x = 0;
	char c = getchar();
	while(c < '0' ||c > '9')
	{
		c = getchar();
	}
	while(c < '0' && c > '9')
	{
		x = x * 10 + c - '0';
		c = getchar();
	} 
}
struct node
{
	int wei;
	long long f;
};
node q[800005];
long long qurey(long long x)
{
long long  rt = 0;
	for(int i = x; i; i -= i&-i)
	{
		rt += f[i];
	}
	return rt;
}
void modify(int a,int b)
{
	for(int i = a; i <= n; i += i&-i)
	{
		f[i] += b;
	}
}
void build(int o,int l,int r)
{
	int mid = (l + r) /2;
	q[o].f = 1e18;
	if(l == r) return;
	build(o*2,l,mid);
	build(o*2+1,mid+1,r);
}
void  update(int o)
{
	if(q[o*2].f < q[o*2+1].f)
	{
		q[o] = q[o*2];
	}
    else
		q[o] = q[o*2+1];
}
void modify1(int o, int l, int r, int pos, long long val)
{
	if(l == r)
	{
		q[o].f= val;
		q[o].wei = pos;
		return;
	}
	int mid = (l + r) >> 1;
	if(pos <= mid) modify1(o*2, l, mid, pos, val);
	if(pos > mid) modify1(o*2+1, mid + 1, r, pos, val);
    update(o);
} 
node qurey1(int o, int l, int r, int ql,int qr)
{
	if(ql <= l && r <= qr)
	{
		return q[o];
	}
	int mid = (l + r) >> 1;
	node rt, he, ha;
	rt.f = 1e18;
	if(ql <= mid)
	{
		he = qurey1(o*2,l,mid,ql,qr);
	    if(he.f < rt.f)
	    {
	    	rt = he;
	    }
	}
	if(mid < qr)
	{
		ha = qurey1(o*2+1, mid+1, r, ql, qr);
		if(ha.f < rt.f)
		{
			rt = ha;
		}
	}
	return rt; 
}
int main()
{
	long long ans = 0;
	freopen("count.in","r",stdin);
	freopen("count.out","w",stdout);
	scanf("%d%d",&n,&m);
	build(1,1,n);
	for(int i = 1; i <= n; i++)
	scanf("%lld",&a[i]);
    for(int i = n; i  >= 1; i--)
    {
    	b[i] = qurey(a[i]-1);
    	ans += b[i];
    	modify1(1,1,n,i,a[i]);
    	modify(a[i],1);
    }
    cout <<ans<< " " ;
    for(int i = 1; i <= m; i++)
    {
    	int l, cnt = 0;
		long long ans1 = 0;
    	scanf("%d",&l);
        while(1)
        {
        	node ha = qurey1(1,1,n,l,n);
        	if(ha.f > a[l]) break;
        	ans1 += b[ha.wei];
        	modify1(1,1,n,ha.wei,1e9);
        }
    	ans -= ans1;
       if(i != m)
    	printf("%lld ", ans);
       else printf("%lld",ans) ;
	}
    return 0;
}