제출 #285657

#제출 시각아이디문제언어결과실행 시간메모리
285657MKopchevRectangles (IOI19_rect)C++14
100 / 100
4124 ms572024 KiB
#include "rect.h"
#include<bits/stdc++.h>
using namespace std;

const int nmax=2500+42,ST=1<<13,ADD=1<<12;

int bigger_up[nmax][nmax],bigger_down[nmax][nmax],bigger_right[nmax][nmax],bigger_left[nmax][nmax];

int tree_up[nmax][ST];

int WANTED_AT_LEAST,WANTED_AT_MOST;

void build_up(int id,int l,int r)
{
    for(int i=ST-1;i>=ADD;i--)
    {
        int where=i-ADD;
        if(where<r)tree_up[id][i]=bigger_up[id][where];
    }

    for(int i=ADD-1;i>=1;i--)
    {
        tree_up[id][i]=max(tree_up[id][i*2],tree_up[id][i*2+1]);
    }
}

int query_up(int id,int node,int l,int r,int lq,int rq)
{
    lq=lq+ADD;
    rq=rq+ADD;

    while(lq<=rq)
    {
        if(tree_up[id][lq]>=WANTED_AT_LEAST)return 1;
        if(tree_up[id][rq]>=WANTED_AT_LEAST)return 1;

        lq=(lq+1)/2;
        rq=(rq-1)/2;
    }
    return 0;
}


int tree_down[nmax][ST];

void build_down(int id,int node,int l,int r)
{
    if(l==r)
    {
        tree_down[id][node]=bigger_down[id][l];
        return;
    }
    int av=(l+r)/2;

    build_down(id,node*2,l,av);
    build_down(id,node*2+1,av+1,r);

    tree_down[id][node]=min(tree_down[id][node*2],tree_down[id][node*2+1]);
}

int fast_down_left(int id,int node,int l,int r,int lq,int rq)
{
    while(tree_down[id][node]<=WANTED_AT_MOST)
    {
        if(l==lq&&r==rq)return 1;

        int av=(l+r)/2;

        if(av<lq)
        {
            l=av+1;
            node=node*2+1;
            continue;
        }

        if(tree_down[id][node*2+1]<=WANTED_AT_MOST)return 1;

        node=node*2;

        r=av;
        rq=av;
    }

    return 0;
}

int fast_down_right(int id,int node,int l,int r,int lq,int rq)
{
    while(tree_down[id][node]<=WANTED_AT_MOST)
    {
        if(l==lq&&r==rq)return 1;

        int av=(l+r)/2;

        if(rq<=av)
        {
            r=av;
            node=node*2;
            continue;
        }

        if(tree_down[id][node*2]<=WANTED_AT_MOST)return 1;

        node=node*2+1;

        l=av+1;
        lq=av+1;
    }

    return 0;
}

int query_down(int id,int node,int l,int r,int lq,int rq)
{
    //cout<<"query_down "<<id<<" "<<node<<" "<<l<<" "<<r<<" "<<lq<<" "<<rq<<endl;

    while(tree_down[id][node]<=WANTED_AT_MOST)
    {
        if(l==lq&&r==rq)return 1;

        int av=(l+r)/2;

        if(rq<=av)
        {
            node=node*2;
            r=av;
            continue;
        }
        if(av<lq)
        {
            node=node*2+1;
            l=av+1;
            continue;
        }
        if(fast_down_left(id,node*2,l,av,lq,av))return 1;
        return fast_down_right(id,node*2+1,av+1,r,av+1,rq);
    }
    return 0;
}




int tree_left[nmax][ST];

void build_left(int id,int l,int r)
{
    for(int i=ST-1;i>=ADD;i--)
    {
        int where=i-ADD;
        if(where<r)tree_left[id][i]=bigger_left[where][id];
    }

    for(int i=ADD-1;i>=1;i--)
    {
        tree_left[id][i]=max(tree_left[id][i*2],tree_left[id][i*2+1]);
    }
}

int query_left(int id,int node,int l,int r,int lq,int rq)
{
    lq=lq+ADD;
    rq=rq+ADD;

    while(lq<=rq)
    {
        if(tree_left[id][lq]>=WANTED_AT_LEAST)return 1;
        if(tree_left[id][rq]>=WANTED_AT_LEAST)return 1;

        lq=(lq+1)/2;
        rq=(rq-1)/2;
    }
    return 0;
}



int tree_right[nmax][ST];

void build_right(int id,int node,int l,int r)
{
    if(l==r)
    {
        tree_right[id][node]=bigger_right[l][id];
        return;
    }
    int av=(l+r)/2;

    build_right(id,node*2,l,av);
    build_right(id,node*2+1,av+1,r);

    tree_right[id][node]=min(tree_right[id][node*2],tree_right[id][node*2+1]);
}

int fast_right_left(int id,int node,int l,int r,int lq,int rq)
{
    while(tree_right[id][node]<=WANTED_AT_MOST)
    {
        if(l==lq&&r==rq)return 1;

        int av=(l+r)/2;

        if(av<lq)
        {
            l=av+1;
            node=node*2+1;
            continue;
        }

        if(tree_right[id][node*2+1]<=WANTED_AT_MOST)return 1;

        node=node*2;

        r=av;
        rq=av;
    }

    return 0;
}

int fast_right_right(int id,int node,int l,int r,int lq,int rq)
{
    while(tree_right[id][node]<=WANTED_AT_MOST)
    {
        if(l==lq&&r==rq)return 1;

        int av=(l+r)/2;

        if(rq<=av)
        {
            r=av;
            node=node*2;
            continue;
        }

        if(tree_right[id][node*2]<=WANTED_AT_MOST)return 1;

        node=node*2+1;

        l=av+1;
        lq=av+1;
    }

    return 0;
}

int query_right(int id,int node,int l,int r,int lq,int rq)
{
    //cout<<"query_right "<<id<<" "<<node<<" "<<l<<" "<<r<<" "<<lq<<" "<<rq<<endl;

    while(tree_right[id][node]<=WANTED_AT_MOST)
    {
        if(l==lq&&r==rq)return 1;

        int av=(l+r)/2;

        if(rq<=av)
        {
            node=node*2;
            r=av;
            continue;
        }
        if(av<lq)
        {
            node=node*2+1;
            l=av+1;
            continue;
        }
        if(fast_right_left(id,node*2,l,av,lq,av))return 1;
        return fast_right_right(id,node*2+1,av+1,r,av+1,rq);
    }
    return 0;
}



stack<int> active,idle;

int pointer=0;

struct rect
{
    int x1,y1,x2,y2;
};

rect to_test[nmax*nmax];

bool cmp(rect a,rect b)
{
    if(a.x1!=b.x1)return a.x1<b.x1;
    if(a.y1!=b.y1)return a.y1<b.y1;
    if(a.x2!=b.x2)return a.x2<b.x2;
    return a.y2<b.y2;
}

bool eq(rect a,rect b)
{
    return a.x1==b.x1&&a.y1==b.y1&&a.x2==b.x2&&a.y2==b.y2;
}

int n,m;

bool test(rect a)
{
    //cout<<"to test "<<a.x1<<" "<<a.y1<<" "<<a.x2<<" "<<a.y2<<endl;

    WANTED_AT_LEAST=a.x1;

    if(query_up(a.x2+1,1,0,m-1,a.y1,a.y2))return 0;

    WANTED_AT_MOST=a.x2;

    if(query_down(a.x1-1,1,0,m-1,a.y1,a.y2))return 0;

    WANTED_AT_LEAST=a.y1;

    if(query_left(a.y2+1,1,0,n-1,a.x1,a.x2))return 0;

    WANTED_AT_MOST=a.y2;

    if(query_right(a.y1-1,1,0,n-1,a.x1,a.x2))return 0;

    return 1;
}

vector< vector<int> > inp;

void eval(int type)//1=> bigger, 0=> bigger or equal
{
    n=inp.size();
	m=inp[0].size();

	for(int i=0;i<n;i++)
    {
        active=idle;

        for(int j=0;j<m;j++)
        {
            while(active.size()&&inp[i][active.top()]+type<=inp[i][j])active.pop();

            if(active.size())bigger_left[i][j]=active.top();
            else bigger_left[i][j]=-1;

            active.push(j);
        }
    }

    for(int i=0;i<n;i++)
    {
        active=idle;

        for(int j=m-1;j>=0;j--)
        {
            while(active.size()&&inp[i][active.top()]+type<=inp[i][j])active.pop();

            if(active.size())bigger_right[i][j]=active.top();
            else bigger_right[i][j]=m;

            active.push(j);
        }
    }

    for(int j=0;j<m;j++)
    {
        active=idle;

        for(int i=0;i<n;i++)
        {
            while(active.size()&&inp[active.top()][j]+type<=inp[i][j])active.pop();

            if(active.size())bigger_up[i][j]=active.top();
            else bigger_up[i][j]=-1;

            active.push(i);
        }
    }

    for(int j=0;j<m;j++)
    {
        active=idle;

        for(int i=n-1;i>=0;i--)
        {
            while(active.size()&&inp[active.top()][j]+type<=inp[i][j])active.pop();

            if(active.size())bigger_down[i][j]=active.top();
            else bigger_down[i][j]=n;

            active.push(i);
        }
    }
}

long long count_rectangles(std::vector<std::vector<int> > a)
{
    inp=a;

    int n=inp.size();
	int m=inp[0].size();

    eval(0);
    /*
    for(int i=0;i<n;i++)
        for(int j=0;j<m;j++)
        {
            cout<<i<<" "<<j<<" -> "<<bigger_up[i][j]<<" "<<bigger_right[i][j]<<" "<<bigger_down[i][j]<<" "<<bigger_left[i][j]<<endl;
        }
    */

    pointer=0;

    for(int i=1;i<n-1;i++)
        for(int j=1;j<m-1;j++)
        {
            rect cur;

            cur.x1=bigger_up[i][j]+1;
            cur.y1=bigger_left[i][j]+1;
            cur.x2=bigger_down[i][j]-1;
            cur.y2=bigger_right[i][j]-1;

            //cout<<i<<" "<<j<<" -> "<<cur.x1<<" "<<cur.y1<<" "<<cur.x2<<" "<<cur.y2<<endl;

            if(1<=cur.x1&&cur.x2<=n-2&&1<=cur.y1&&cur.y2<=m-2)
            {
                pointer++;

                to_test[pointer]=cur;
            }
        }

    sort(to_test+1,to_test+pointer+1,cmp);

    eval(1);

    for(int i=0;i<n;i++)
    {
        build_up(i,0,m-1);
        build_down(i,1,0,m-1);
    }

    for(int j=0;j<m;j++)
    {
        build_right(j,1,0,n-1);
        build_left(j,0,n-1);
    }

    int outp=0;

    for(int i=1;i<=pointer;i++)
    {
        if(eq(to_test[i-1],to_test[i]))continue;

        outp+=test(to_test[i]);
    }

    return outp;
}
#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...