JZOJ 5222. 【GDOI2018模擬7.12】A (Standard IO)
阿新 • • 發佈:2018-12-12
題目連結:
Click here
Solution
設
表示
與它後面的數形成的逆序對個數。
為原來數列逆序對個數。
每次詢問一個
,對於滿足
並且
的所有
,若
並且
,那麼
形成了逆序對。但由於
,所以這些
都會被排好序,變成了
並且
,這些
的逆序對也就全都被消去了,也就是說
要減去這些
。
直接上樹套樹orCDQ?不存在的。因為一個
在某一次詢問被消去影響之後,就不會再被消去,所以線上的做法沒法做。那麼考慮離線,按照詢問的修改位置排序,詢問
能夠消去位置
的影響的條件是
且
。設
表示
是第幾個詢問,那麼
最早消去影響的時間就是滿足
且
的最小的
。
這是個二維偏序問題,按照
排序後一維被消掉,條件
用樹狀陣列維護字尾最小值即可。
至於當詢問
對應的
被某個詢問
修改的情況,我們只需要用原來沒被修改過的的
即可,因為如果
被
改了,說明
後面的逆序對早就被詢問
消完了,我們即使把這個詢問加進去也不會影響答案。
然後此題完。
Code
由於using namespace std
被ban掉了,為了鞏固基礎知識,我自己實現了歸併排序、離散化、二分等演算法,導致碼量大了一點,但是讓我對基礎演算法理解加深了更多。
#include <cstdio>
#include <cstring>
#include <cstdlib>
typedef long long ll;
const int N = 100007;
const ll INF = 0x3f3f3f3f;
int min(int a, int b) { return a < b ? a : b; }
int n, m, len, a[N], val[N], arr[N], temp[N];
ll sum[N];
struct note { int po, tim, val; } q[N], tmp[N];
int operator<(note a, note b) { return a.po < b.po; }
void sortq(int l, int r)
{
if (l == r) return;
int mid = l + r >> 1;
sortq(l, mid), sortq(mid + 1, r);
int i = l, j = mid + 1, len = 0;
while (j <= r)
{
while (i <= mid && q[i] < q[j]) tmp[++len] = q[i++];
tmp[++len] = q[j++];
}
while (i <= mid) tmp[++len] = q[i++];
for (int i = 1; i <= len; i++) q[l + i - 1] = tmp[i];
}
void sort(int l, int r)
{
if (l == r) return;
int mid = l + r >> 1;
sort(l, mid), sort(mid + 1, r);
int i = l, j = mid + 1, len = 0;
while (j <= r)
{
while (i <= mid && arr[i] <= arr[j]) temp[++len] = arr[i++];
temp[++len] = arr[j++];
}
while (i <= mid) temp[++len] = arr[i++];
for (int i = 1; i <= len; i++) arr[l + i - 1] = temp[i];
}
void unique()
{
len = 0;
int i = 1;
while (i <= n)
{
arr[++len] = arr[i++];
while (i <= n && arr[i] == arr[i - 1]) i++;
}
}
int lower_bound(int val)
{
int l = 1, r = len, mid, ans;
while (l <= r)
{
mid = l + r >> 1;
if (arr[mid] >= val) r = mid - 1, ans = mid;
else l = mid + 1;
}
return ans;
}
int tr[N][2];
void add(int po, int k, int v)
{
for (; po <= n; po += (po & (-po)))
{
if (k) tr[po][k] = min(tr[po][k], v);
else tr[po][k] += v;
}
}
int query(int po, int k)
{
int ret = k ? INF : 0;
for (; po; po -= (po & (-po)))
{
if (k) ret = min(ret, tr[po][k]);
else ret += tr[po][k];
}
return ret;
}
int main()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) scanf("%d", a + i);
memcpy(arr, a, sizeof(a));
sort(1, n);
unique();
for (int i = n; i >= 1; i--) a[i] = lower_bound(a[i]), val[i] = query(a[i] - 1, 0), add(a[i], 0, 1), sum[0] += val[i];
for (