제출 #1190081

#제출 시각아이디문제언어결과실행 시간메모리
1190081alexddRectangles (IOI19_rect)C++20
37 / 100
5106 ms520076 KiB
#pragma GCC optimize("O3,unroll-loops")
#include "rect.h"
#include<iostream>
#include<cassert>
#include<algorithm>
using namespace std;
int n,m;
vector<pair<int,int>> get_bune(const vector<int>&v)
{
    vector<pair<int,int>> bune;
    vector<int> dq;
    for(int i=0;i<v.size();i++)
    {
        while(!dq.empty() && v[i] > v[dq.back()])
        {
            if(dq.back()+1 <= i-1)
                bune.push_back({dq.back()+1,i-1});
            dq.pop_back();
        }
        if(!dq.empty() && dq.back()+1 <= i-1)
            bune.push_back({dq.back()+1,i-1});
        if(!dq.empty() && v[dq.back()] == v[i])
            dq.pop_back();
        dq.push_back(i);
    }
    //sort(bune.begin(),bune.end());
    return bune;
}
vector<pair<int,int>> bune_pe_rand[2505];
vector<int> coloane_bune[2505][2505];
vector<int> randuri_bune[2505][2505],primu[2505][2505];
int poz_rbune[2505][2505];

/*int aib[2505][2505];
int qry(int x, int y)
{
    x++;
    y++;
    int aux=0;
    for(int i=x;i<=m;i+=(i&(-i)))
        for(int j=y;j>0;j-=(j&(-j)))
            aux += aib[i][j];
    return aux;
}
void upd(int x, int y, int newv)
{
    x++;
    y++;
    for(int i=x;i>0;i-=(i&(-i)))
        for(int j=y;j<=m;j+=(j&(-j)))
            aib[i][j] += newv;
}*/

vector<int> aib[2505];
int cntscos[2505][2505];
void baga(int x, int y)
{
    x++;
    y++;

    int aux=0;
    for(int i=x;i>0;i-=(i&(-i)))
        aib[i].push_back(y);
}
void init()
{
    for(int i=1;i<=m;i++)
    {
        sort(aib[i].begin(),aib[i].end());
        reverse(aib[i].begin(),aib[i].end());
    }
}
void scoate(int x, int y)//------------------------------------------------------
{
    x++;
    y++;

    for(int i=x;i>0;i-=(i&(-i)))
        cntscos[i][y]++;
}
int qry(int x, int y)
{
    x++;
    y++;

    int aux=0;
    for(int i=x;i<=m;i+=(i&(-i)))
    {
        vector<int> debagat;
        for(int j=(int)aib[i].size()-1;j>=0;j--)
        {
            if(aib[i][j] > y)
                break;
            if(cntscos[i][aib[i][j]] > 0)
            {
                cntscos[i][aib[i][j]]--;
            }
            else
            {
                debagat.push_back(aib[i][j]);
                aux++;
            }
            aib[i].pop_back();
        }
        for(int j=(int)debagat.size()-1;j>=0;j--)
            aib[i].push_back(debagat[j]);
    }
    return aux;
}

vector<pair<int,int>> scoase[2505];

long long count_rectangles(std::vector<std::vector<int>> a)
{
    n = a.size();
    m = a[0].size();
    long long rez=0;
    for(int i=1;i+1<a.size();i++)
    {
        bune_pe_rand[i] = get_bune(a[i]);
        for(auto [x,y]:bune_pe_rand[i])
            randuri_bune[x][y].push_back(i);
    }
    for(int x=1;x+1<m;x++)
    {
        for(int y=x;y+1<m;y++)
        {
            if(randuri_bune[x][y].empty())
                continue;
            primu[x][y].resize(randuri_bune[x][y].size() + 2);
            int ult = a.size();
            if(randuri_bune[x][y].back() != (int)a.size() - 2)
                ult = randuri_bune[x][y].back() + 1;
            primu[x][y][randuri_bune[x][y].size()] = ult;
            for(int i=randuri_bune[x][y].size()-1;i>0;i--)
            {
                if(randuri_bune[x][y][i] != randuri_bune[x][y][i-1] + 1)
                    ult = randuri_bune[x][y][i-1] + 1;
                primu[x][y][i] = ult;
            }
        }
    }
    for(int i=1;i+1<m;i++)
    {
        vector<int> aux;
        for(int j=0;j<a.size();j++)
            aux.push_back(a[j][i]);
        vector<pair<int,int>> bune = get_bune(aux);
        for(auto [x,y]:bune)
            coloane_bune[x][y].push_back(i);
    }
    for(int sus=1;sus+1<a.size();sus++)
    {
        for(int jos=sus;jos<=a.size();jos++)
            scoase[jos].clear();
        for(auto [x,y]:bune_pe_rand[sus])
        {
            baga(x,y);
            while(randuri_bune[x][y][poz_rbune[x][y]] < sus)
                poz_rbune[x][y]++;
            scoase[primu[x][y][poz_rbune[x][y]+1]].push_back({x,y});
        }
        init();
        for(int jos=sus;jos+1<a.size();jos++)
        {
            //for(int i=0;i<scoase[jos].size();i++) upd(scoase[jos][i].first,scoase[jos][i].second,-1);
            for(auto [x,y]:scoase[jos]) scoate(x,y);
            //for(pair<int,int> x:scoase[jos]) upd(x.first,x.second,-1);


            if(!coloane_bune[sus][jos].empty())
            {
                int ult=0;
                for(int i=0;i+1<coloane_bune[sus][jos].size();i++)
                {
                    if(coloane_bune[sus][jos][i] + 1 != coloane_bune[sus][jos][i+1])
                    {
                        rez += qry(coloane_bune[sus][jos][ult],coloane_bune[sus][jos][i]);
                        ult = i+1;
                    }
                }
                rez += qry(coloane_bune[sus][jos][ult],coloane_bune[sus][jos][coloane_bune[sus][jos].size() - 1]);
            }

        }
        for(auto [x,y]:scoase[a.size()]) scoate(x,y);
    }
    assert(rez <= 4*n*m);
    return rez;
}
/*

ne fixam linia de sus
apoi mergem cu linia de jos in jos, o sa avem la inceput O(N) perechi de coloane candidate
cand adaugam o linie in jos o sa dezactivam niste perechi de coloane

trebuie sa verificam pt fiecare (sus,jos) care coloane sunt bune

asta o sa fie O(N^2), pt ca fiecare coloana o sa apara in O(N) (sus,jos)-uri

facem un dsu in care tinem si candidatii de perechi de coloane si cam asta e tot sper

*/
#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...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...