2018年5月18日 星期五

(IOI) 2008 Day 2 p2 Pyramid Base

https://contest.yandex.com/ioi/contest/567/problems/E/

首先,答案的正方形的長度可以二分搜,所以,我們可以先把問題轉成:有沒有一個長度為X的正方形,可以成功地放進格子裡面。

那,我們也可以輕易地算出:題目的那P個矩形中,每一個矩形會影響到多少 " 左上角放在某個格子的正方形 " ,注意到現在正方形的長度已經被限制成X了。

那,有了這些之後,我們就可以使用掃描線囉~

你需要一顆線段樹,可以支援:
(1) 區間加值
(2) 區間減值
(3) 查詢整體的min。

如果掃到某一個時間,當下整體的min <= B,那就代表可以放。

這樣的複雜度是O(P * log P * log( min(n,m) )),最後一筆subtask過不了QAQ。

最後一筆有一個很神奇(?)的特性:B = 0。

首先,我們先定義一個一個函數 F(x1,x2):代表說,在 x 座標是介於 [x1, x2]的區域中,連續 y 座標都是空的最大長度是多少。

可以發現: F(x1,x2) >= F(x1-1, x2) && F(x1,x2) >= F(x1,x2+1)

可以發現,如果固定x1,當x2越大的時候,F(x1,x2)會越來越小

當x2固定時,隨著x1越來越大,F(x1,x2)會越來越大

於是,我們可以使用雙指針來維護x1,x2,如果當下F(x1,x2) >= x2-x1+1,代表我們找到一個邊長為x2-x1+1的三角形,並且可以移動x2的指針。

如果當下F(x1,x2) < x2 - x1 +1,我們就要移動x1的指針的。

所以,我們需要一個資料結構(線段樹),維護:
(1) 加入一個線段
(2) 刪除一個線段
(3) 查詢當前狀態的F值

可以用類似 " 區間連續最大和 " 的線段樹來解決。

//really hard QAQ
#include <bits/stdc++.h>
using namespace std;

typedef pair<int,int> Pt;
typedef pair<int,int> pii;
typedef pair<pii,pii> Rec;

#define F first
#define S second
#define MP make_pair
#define SZ(x) ((int)(x).size())

int n,m,b;
int p;
const int N = 400006;

Rec rr[N];
Rec rrr[N];
int c[N];

vector<pii> Event[800006];  //MP(+ or - , index(to get y range) )

struct Node
{
    static Node mem[4*200006];
    Node *lc,*rc;
    int mn,tag;
    Node():lc(NULL),rc(NULL),tag(0),mn(0){}
    void pull()
    {
        mn = min(lc->mn,rc->mn);
    }
} Node::mem[4*200006],*ptr = Node::mem;

Node* Build(int L,int R)
{
    Node* node = new(ptr++)Node();
    if (L==R) return node;
    int mid=(L+R)>>1;
    node->lc = Build(L,mid);
    node->rc = Build(mid+1,R);
    return node;
}

void push(Node* node,int L,int R)
{
    if (L==R) node->tag = 0;
    if (node->tag == 0)return;
    node->lc->mn += node->tag;
    node->rc->mn += node->tag;
    node->lc->tag += node->tag;
    node->rc->tag += node->tag;
    node->tag = 0;
    return;
}

void modify(Node* node, int L,int R,int l,int r,int del)
{
    if (l>R || L>r) return;
    else if (l<=L &&R<=r)
    {
        node->mn += del;
        node->tag += del;
        return;
    }
    push(node,L,R);
    int mid=(L+R)>>1;
    modify(node->lc,L,mid,l,r,del);
    modify(node->rc,mid+1,R,l,r,del);
    node->pull();
    return;
}

bitset<1000006> vis_x,vis_y,ee;

bool can_0(int len)
{
    if (len >= min(n,m)+1) return false;
    ptr = Node::mem;
    int nn = n-len+1, mm = m-len+1;
    int pp=0;
    vector<int> vx,vy;
    vis_x = ee;
    vis_y = ee;
    for (int i=1;p>=i;i++)
    {
        int x1 = rr[i].F.F - len+1;
        int y1 = rr[i].F.S - len+1;
        int x2 = rr[i].S.F;
        int y2 = rr[i].S.S;
        x1 = max(x1,1);
        y1 = max(y1,1);
        if (x1 <= nn && y1 <= mm)
        {
            x2 = min(x2,nn);
            y2 = min(y2,mm);
            //if (x1 == 1 && y1 == 1 && x2 == nn && y2 == mm) return false;
            rrr[++pp] = MP( MP(x1,y1) , MP(x2,y2) );
            if (!vis_x[x1]) vx.push_back(x1);
            vis_x[x1] = true;
            if (x2 + 1 <= nn && !vis_x[x2+1]) vx.push_back(x2+1);
            vis_x[x2+1] = true;
            if (!vis_y[y1]) vy.push_back(y1);
            vis_y[y1] = true;
            if (1 <= y1-1 && !vis_y[y1-1]) vy.push_back(y1-1);
            vis_y[y1-1] = true;
            if (!vis_y[y2]) vy.push_back(y2);
            vis_y[y2] = true;
            if (y2+1 <= mm && !vis_y[y2+1]) vy.push_back(y2+1);
            vis_y[y2+1] = true;
        }
    }
    if (pp == 0) return true;
    vx.push_back(1); vx.push_back(nn);
    vy.push_back(1); vy.push_back(mm);
    sort(vx.begin(),vx.end()); vx.resize(unique(vx.begin(),vx.end()) - vx.begin());
    sort(vy.begin(),vy.end()); vy.resize(unique(vy.begin(),vy.end()) - vy.begin());
    //y axis --> segment tree
    for (int i=0;SZ(vx)>=i;i++)
    {
        Event[i].clear();
    }
    for (int i=1;pp>=i;i++)
    {
        int x1=rrr[i].F.F;
        int pos = lower_bound(vx.begin(),vx.end(),x1) - vx.begin() + 1;
        Event[pos].push_back(make_pair(1,i));
        rrr[i].F.S = lower_bound(vy.begin(),vy.end(),rrr[i].F.S) - vy.begin() + 1;
        rrr[i].S.S = lower_bound(vy.begin(),vy.end(),rrr[i].S.S) - vy.begin() + 1;
    }
    //cout << "len = " << len << endl;
    int mmm = SZ(vy);
    Node* root = Build(1,mmm);
    for (int i=1;SZ(vx)>=i;i++)
    {
        for (pii p:Event[i])
        {
            if (p.F == -1) modify(root,1,mmm,rrr[ p.S ].F.S,rrr[ p.S ].S.S,-c[ p.S ]);
            else
            {
                modify(root,1,mmm,rrr[ p.S ].F.S,rrr[p.S].S.S, c[p.S] );
                int x2 = rrr[p.S].S.F;
                if (x2+1 <= nn)
                {
                    int _ = x2+1;
                    int pos = lower_bound(vx.begin(),vx.end(),_) - vx.begin() + 1;
                    Event[pos].push_back(make_pair(-1,p.S));
                }
            }
        }
        push(root,1,mmm);
        //cout << "i = " << i << " , len = " << len << " root->mn = " << root->mn << endl;
        if (root->mn <= b)
        {
            return true;
        }
    }
    return false;
    //return true;
}

void solve()
{
    for (int i=1;p>=i;i++)
    {
        scanf("%d %d %d %d %d",&rr[i].F.F,&rr[i].F.S,&rr[i].S.F,&rr[i].S.S,&c[i]);
    }
    int L=0,R=1000006;
    while (R-L != 1)
    {
        int mid=(L+R)>>1;
        //cout << "mid = " << mid << endl;
        if (can_0(mid)) L = mid;
        else R = mid;
    }
    printf("%d\n",L);
}

struct Sagiri
{
    Sagiri *lc,*rc;
    int Lmax,Rmax,midmax;
    int cnt;
    int L,R;
    Sagiri(){}
    Sagiri(int _L,int _R):L(_L),R(_R),Lmax(0),Rmax(0),midmax(0),cnt(0){}
    void pull()
    {
        if (cnt)
        {
            Lmax = Rmax = midmax = 0;
            return;
        }
        else if (L==R)
        {
            Lmax = Rmax = midmax = 1;
            return;
        }
        int mid=(L+R)>>1;
        Lmax = (lc->Lmax == mid-L+1 ? lc->Lmax + rc->Lmax : lc->Lmax);
        Rmax = (rc->Rmax == R-mid ? rc->Rmax + lc->Rmax : rc->Rmax);
        midmax = max( max( lc->midmax , rc->midmax ) , lc->Rmax + rc->Lmax );
    }
};

Sagiri* Buildd(int L,int R)
{
    Sagiri* sagiri = new Sagiri(L,R);
    if (L==R)
    {
        sagiri->pull();
        return sagiri;
    }
    int mid=(L+R)>>1;
    sagiri->lc = Buildd(L,mid);
    sagiri->rc = Buildd(mid+1,R);
    sagiri->pull();
    return sagiri;
}

void modifyy(Sagiri* sagiri,int L,int R,int l,int r,int del)
{
    if (l>R || L>r) return;
    else if (l<=L && R<=r)
    {
        sagiri->cnt += del;
        sagiri->pull();
        return;
    }
    int mid=(L+R)>>1;
    modifyy(sagiri->lc,L,mid,l,r,del);
    modifyy(sagiri->rc,mid+1,R,l,r,del);
    sagiri->pull();
    return;
}

const int P = 1000006;

vector<int> addd[P],subb[P];

int main ()
{
    scanf("%d %d %d",&n,&m,&b);
    scanf("%d",&p);
    if (p <= 30000)
    {
        solve();
        return 0;
    }
    Sagiri* root = Buildd(1,m);
    for (int i=1;p>=i;i++)
    {
        scanf("%d %d %d %d %d",&rr[i].F.F,&rr[i].F.S,&rr[i].S.F,&rr[i].S.S,&c[i]);
        addd[ rr[i].F.F ].push_back(i);
        subb[ rr[i].S.F ].push_back(i);
    }
    int ans=0;
    int L=1;
    for (int R=1;n>=R;R++)
    {
        for (int i:addd[R])
        {
            modifyy(root,1,m,rr[i].F.S,rr[i].S.S,1);
        }
        //cout << "L = " << L << " , R = " << R<<" , midmax = " << root->midmax << endl;
        if (root->midmax >= R-L+1) ans = max(ans,R-L+1);
        while (root->midmax < R-L+1)
        {
            for (int i:subb[L])
            {
                modifyy(root,1,m,rr[i].F.S,rr[i].S.S,-1);
            }
            ++L;
        }
    }
    printf("%d\n",ans);
}

沒有留言:

張貼留言