2019-2020 ICPC Southeastern European Regional Programming Contest (SEERC 2019) 補題記錄

Yjmstr發表於2020-12-10

A.max or min
CF上ac了洛谷wa1?
好神啊不會做
去膜了下官方題解 並跟著寫了一發線段樹 結果寫掛了沒調出來
後來換珂朵莉樹T爆了
bzy:set維護線段不是很常見的操作嗎 你怎麼寫到100行的
我:。。。。。

做法如下
注意到有意義的只是當前數字與目標數字的大小關係
我們可以令小於當前數字的數全部變成-1 大於則為1 等於為0
考慮以下情況
如果序列是0 1 1 1 或者0 -1 -1 -1 要讓他們變成0只要進行(n-(0的個數))次操作即可
如果是0 -1 1 -1 這樣的交替序列 如果 -1 1 -1 1 這樣的交替序列長為L
我們要先讓他們全部變成1或者-1 再全部變成0
於是操作次數就多了L/2向下取整次
我們記sumz為一共要多操作的次數 則答案為n-目標數字的出現次數+sumz
我們要維護每個交替串的起點終點和長度
對於不是環的情況求出sumz 對於是環的情況就可以特判一下1和n位置能不能形成交替串 如果能就更新一下答案
通過set可以在log時間內找出某個位置所屬交替串的起點終點
然後我們要實現upd(pos,val)操作 把陣列pos的位置修改 為val
注意到val若為-1 則之前pos位置必為0 若val為0 則pos位置之前必為1
這樣就可以找出交替串 並且一點一點更改目標數值求出所有答案了

#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 7;
typedef pair<int, int> pii;
set<pii, less<pii> > s;
#define IT set<pii, less<pii> > :: iterator
int a[maxn], n, m, sumz, ans;
vector<int> _[maxn];
void upd(int pos, int val) {
    if (val == 0) {  //1改成0
        a[pos] = 0;
        IT it = s.lower_bound(make_pair(pos, pos));
        if (it == s.end() || it->first != pos) it--;
        pii u = *it; 
        s.erase(u);
        sumz -= (u.second - u.first + 1) / 2;
        if (u.first < pos) {
            s.insert(make_pair(u.first, pos-1));
            sumz += (pos - u.first) / 2;
        }
        if (u.second > pos) {
            s.insert(make_pair(pos + 1, u.second));
            sumz += (u.second - pos) / 2;
        }
    } else if (val == -1) {//0改-1 接起來兩段
        a[pos] = -1; 
        if (pos < n && a[pos + 1] == 1) {
            IT it = s.lower_bound(make_pair(pos + 1, pos + 1));
            if (it == s.end() || it->first != pos + 1) it--;
            pii u = *it;
            s.erase(u); 
            sumz -= (u.second-u.first + 1) / 2;
            s.insert(make_pair(pos, u.second));
            sumz += (u.second - pos + 1) / 2;
        } else s.insert(make_pair(pos, pos));
        if (pos > 1 && a[pos - 1] == 1) {
            IT it = s.lower_bound(make_pair(pos-1, pos-1)), it2 = s.lower_bound(make_pair(pos, pos));
            if (it == s.end() || it->first != pos - 1) it--;
            //if (it2 == s.end() || it2->first != pos) it2--;
            pii u = *it, v = *it2;
            sumz -= (u.second - u.first + 1) / 2; 
            sumz -= (v.second - v.first + 1) / 2;
            s.erase(u); 
            s.erase(v);
            sumz += (v.second - u.first + 1) / 2;
            s.insert(make_pair(u.first, v.second));
        }
    }
}
int main() {
    cin >> n >> m;
    for (int i = 1; i <= n; i++) {
        cin >> a[i];
        _[a[i]].push_back(i);
        a[i] = 1;
        s.insert(make_pair(i, i));
    }
    for (int i = 1; i <= m; i++) {
        if (_[i].size() == 0) {
            puts("-1");
            continue;
        }
        for (int j = 0; j < _[i].size(); j++) upd(_[i][j], 0);
        if (a[1] == 0 || a[n] == 0 || a[1] == a[n]) {
            ans = sumz + n - _[i].size();
        } else {
            IT it = s.lower_bound(make_pair(n, n)), it1 = s.lower_bound(make_pair(1,1));
            if (it == s.end() || it->first != n) it--;
            //if (it1 == s.end() || it1->first != 1) it1--;
            ans = sumz - (it->second-it->first+1)/2-(it1->second-it1->first+1)/2+(it1->second-it1->first+it->second-it->first+2)/2 + n - _[i].size();
        }
        cout << ans << "\n";
        for (int j = 0; j < _[i].size(); j++) upd(_[i][j], -1);
    }
}

相關文章