Submission #1018039

#TimeUsernameProblemLanguageResultExecution timeMemory
1018039andrei_iorgulescuPalembang Bridges (APIO15_bridge)C++14
100 / 100
1584 ms139980 KiB
#include <bits/stdc++.h>

using namespace std;

using ll = long long;

ll inf = (ll)1e9 * (ll)1e9;
int tuf = (int)2e9 + 1;
const int NN = 6200000;

int n,k;
char p[100005],q[100005];
int s[100005],t[100005];
ll ans;

ll real_value[200005];
int m;

ll cate_r[200005],sum_r[200005],cate_l[200005],sum_l[200005];
map<int,int> huh;
vector<int> vvv;

void normalize()
{
    set<int> vls;
    for (int i = 1; i <= n; i++)
    {
        vls.insert(s[i]);
        vls.insert(t[i]);
    }
    map<int,int> norma;
    int itr = 0;
    for (auto it : vls)
    {
        itr++;
        norma[it] = itr;
        real_value[itr] = it;
    }
    m = itr;
    for (int i = 1; i <= n; i++)
        s[i] = norma[s[i]],t[i] = norma[t[i]];
    set<int> vls2;
    for (int i = 1; i <= n; i++)
        vls2.insert(real_value[s[i]] + real_value[t[i]]);
    itr = 0;
    for (auto it : vls2)
    {
        itr++;
        huh[it] = itr;
        vvv.push_back(it);
    }
}

int down_lpr(int x)
{
    if (x < vvv[0])
        return 0;
    int st = 0,pas = 1 << 16;
    while (pas != 0)
    {
        if (st + pas < vvv.size() and vvv[st + pas] <= x)
            st += pas;
        pas /= 2;
    }
    return st + 1;
}

int up_lpr(int x)
{
    if (x > vvv.back())
        return 0;
    int st = -1,pas = 1 << 16;
    while (pas != 0)
    {
        if (st + pas < vvv.size() and vvv[st + pas] < x)
            st += pas;
        pas /= 2;
    }
    return st + 2;
}

int y_opt[200005];

pair<int,ll> aint[NN + 5];
int fs[NN + 5],fd[NN + 5];
int roots1[200005],roots2[200005];
int cate;

pair<int,ll> query(int nod, int l, int r, int st, int dr)
{
    if (aint[nod].first == 0)
        return {0,0};
    if (r < st or dr < l)
        return {0,0};
    if (st <= l and r <= dr)
        return aint[nod];
    int mij = (ll)((ll)l + (ll)r) / 2;
    pair<int,ll> p1 = query(fs[nod],l,mij,st,dr),p2 = query(fd[nod],mij + 1,r,st,dr);
    return {p1.first + p2.first,p1.second + p2.second};
}

void update(int nod, int l, int r, int pos, int val)
{
    if (l == r)
    {
        aint[nod].first++;
        aint[nod].second += val;
    }
    else
    {
        int mij = (ll)((ll)l + (ll)r) / 2;
        if (pos <= mij)
        {
            cate++;
            aint[cate] = aint[fs[nod]];
            fs[cate] = fs[fs[nod]];
            fd[cate] = fd[fs[nod]];
            fs[nod] = cate;
            update(fs[nod],l,mij,pos,val);
        }
        else
        {
            cate++;
            aint[cate] = aint[fd[nod]];
            fs[cate] = fs[fd[nod]];
            fd[cate] = fd[fd[nod]];
            fd[nod] = cate;
            update(fd[nod],mij + 1,r,pos,val);
        }
        aint[nod] = {aint[fs[nod]].first + aint[fd[nod]].first,aint[fs[nod]].second + aint[fd[nod]].second};
    }
}

ll f(int x,int y)
{
    ll dev = 0;
    dev += real_value[x] * cate_r[x - 1] - sum_r[x - 1];
    dev += sum_l[y + 1] - real_value[y] * cate_l[y + 1];
    int cn = down_lpr(real_value[x] + real_value[y]);
    pair<int,ll> p1;
    if (cn == 0)
        p1 = {0,0};
    else
        p1 = query(roots1[x],1,n,1,cn);///.first = cate, .second = suma L-urilor reale
    cn = up_lpr(real_value[x] + real_value[y] + 1);
    pair<int,ll> p2;
    if (cn == 0)
        p2 = {0,0};
    else
        p2 = query(roots2[y],1,n,cn,n);///.first = cate, .second = suma R-urilor reale
    dev += p1.second - p1.first * real_value[x];
    dev += p2.first * real_value[y] - p2.second;
    dev *= 2;
    return dev;
}

void solve(int l, int r, int st, int dr)
{
    if (l > r)
        return;
    int mij = (l + r) / 2;
    ll bst = inf;
    for (int i = st; i <= dr; i++)
    {
        ll cat = f(mij,i);
        if (cat < bst)
        {
            bst = cat;
            y_opt[mij] = i;
        }
    }
    solve(l,mij - 1,st,y_opt[mij]);
    solve(mij + 1,r,y_opt[mij],dr);
}

vector<pair<int,int>> cine_r[200005],cine_l[200005];

signed main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);
    cin >> k >> n;
    for (int i = 1; i <= n; i++)
    {
        cin >> p[i] >> s[i] >> q[i] >> t[i];
        if (s[i] > t[i])
            swap(s[i],t[i]);
        ans += t[i] - s[i];
        if (p[i] == q[i])
            n--,i--;
    }
    ans += n;
    if (n <= k)
    {
        cout << ans << '\n';
        return 0;
    }
    normalize();
    //for (int i = 1; i <= n; i++)
      //  cout << s[i] << ' ' << t[i] << endl;
    for (int i = 1; i <= n; i++)
    {
        cine_l[s[i]].push_back({s[i],t[i]});
        cine_r[t[i]].push_back({s[i],t[i]});
    }
    for (int i = 1; i <= n; i++)
    {
        cate_r[t[i]]++;
        sum_r[t[i]] += real_value[t[i]];
        cate_l[s[i]]++;
        sum_l[s[i]] += real_value[s[i]];
    }
    for (int i = 1; i <= m; i++)
    {
        cate_r[i] += cate_r[i - 1];
        sum_r[i] += sum_r[i - 1];
    }
    for (int i = m; i >= 1; i--)
    {
        cate_l[i] += cate_l[i + 1];
        sum_l[i] += sum_l[i + 1];
    }
    if (k == 1)
    {
        ll devmin = inf;
        for (int i = 1; i <= m; i++)
        {
            ll cr = cate_r[i - 1],sr = sum_r[i - 1],cl = cate_l[i + 1],sl = sum_l[i + 1];
            //cout << cr << ' ' << sr << ' ' << cl << ' ' << sl << endl;
            ll x = real_value[i];
            ll dev = 2 * (x * cr - sr + sl - x * cl);
            devmin = min(devmin,dev);
        }
        cout << ans + devmin;
    }
    else
    {
        cate = 2 * m;
        for (int i = 1; i <= m; i++)
            roots1[i] = i;
        for (int i = 1; i <= m; i++)
            roots2[i] = i + m;
        for (int x = m; x >= 1; x--)
        {
            aint[x] = aint[x + 1];
            fs[x] = fs[x + 1];
            fd[x] = fd[x + 1];
            for (auto interval : cine_l[x + 1])
                update(x,1,n,huh[real_value[interval.first] + real_value[interval.second]],real_value[interval.first]);
        }
        for (int y = m + 1; y <= 2 * m; y++)
        {
            if (y != m + 1)
            {
                aint[y] = aint[y - 1];
                fs[y] = fs[y - 1];
                fd[y] = fd[y - 1];
            }
            for (auto interval : cine_r[y - m - 1])
                update(y,1,n,huh[real_value[interval.first] + real_value[interval.second]],real_value[interval.second]);
        }
        solve(1,m,1,m);
        ll devmin = inf;
        for (int i = 1; i <= m; i++)
            devmin = min(devmin,f(i,y_opt[i]));
        cout << ans + devmin;
    }
    return 0;
}

/*
2 5
A 0 B 2
A 6 B 8
A 11 B 13
A 9 B 15
A 13 B 19
*/

/**
Obs: merita sa fac pod doar unde e cv cladire, adica in O(N) locatii
Initial adun abs(S[i] - T[i]) la toate, fac S[i] <= T[i], daca P[i] = Q[i] il elimin, altfel mai adaug 1 si presupun P[i] = A, Q[i] = B
N o sa fie cate intervale au P[i] != Q[i]
K = 1 -> fixez unde fac podul, vad cate au R in stanga si suma R-urilor, cate au L in dreapta si suma L-urilor, cv formula
K = 2

Fie x si y locatiile (dintre cele O(N)) in care imi fac podurile
Cred (doamne ajuta adica) ca daca imi fixez un x, y_opt(x) e crescator (divide dp stuff)
Hai sa zicem ca am eu o functie magica f(x,y) care imi calculeaza suma devierilor daca fac poduri in x si y
Pai f(x,y) functioneaza gen: ia toate alea cu R < x si zice cate si suma, toate cu L > y si zice cate si suma etc penal
Problema apare la alea x < L <= R < y ca am min(L - x, y - R)
Aici, zic asa: fie mij = r[x] + r[y] (omit / 2 ca nu conteaza) si m = r[L] + r[R]
Daca m <= mij, L - x e minim, altfel R - y e minim

Atunci f(x,y) zice: gaseste toti aia cu L > x si m <= mij si zi cati si suma L-urilor (oricum asta imi garanteaza y < R)
Apoi, gaseste toti aia cu R < y si m > mij si zi cati si suma R-urilor (once again, asta garanteaza L > x)

In functie de chestiile alea am o formula penala pentru f(x,y)
Pai nu am update-uri sau ceva, deci pot sa ma uit asa:
- pentru alea cu R < x, doar imi tin ceva cate_r[x] si sum_r[x] (cate r < x si suma valorilor lor reale)
- pentru alea cu L > y, ceva analog pe sufixe
- pentru cate L > x si m <= mij, dat fiind ca nu am update-uri pot sa ma uit in versiunea x si sa intreb chestii pe m <= mij
Adica sa imi tin un aint persistent in care merg cu x de la m la 1 si imi tin pentru fiecare, structura pe alea cu L mai mare
-pentru R < y, m > mij, tot asa, un aint persistent de merg cu y de la 1 la m si tin strucura pe m cu alea cu R < y

Astfel, am o precalculare O(NlogN) timp si memorie si O(logN) timp pe query, deci Nlog^2 total

Hai ca mai stie cineva sa implementeze aint persistent
**/

Compilation message (stderr)

bridge.cpp: In function 'int down_lpr(int)':
bridge.cpp:61:22: warning: comparison of integer expressions of different signedness: 'int' and 'std::vector<int>::size_type' {aka 'long unsigned int'} [-Wsign-compare]
   61 |         if (st + pas < vvv.size() and vvv[st + pas] <= x)
      |             ~~~~~~~~~^~~~~~~~~~~~
bridge.cpp: In function 'int up_lpr(int)':
bridge.cpp:75:22: warning: comparison of integer expressions of different signedness: 'int' and 'std::vector<int>::size_type' {aka 'long unsigned int'} [-Wsign-compare]
   75 |         if (st + pas < vvv.size() and vvv[st + pas] < x)
      |             ~~~~~~~~~^~~~~~~~~~~~
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...