1. 程式人生 > >bzoj 1824: [JSOI2010]下棋問題

bzoj 1824: [JSOI2010]下棋問題

mic 多少 ems 坐標 一個 name 16px style +=

考慮每次新放一個棋子會產生多少新的矩形,以及減掉多少舊的矩形。

用第$i$個點的坐標把坐標軸分成4個象限。

顯然第一問的答案用四個單調棧就能解決。

而且第二問每個矩形的兩個端點一定在1,3或2,4象限的單調棧裏。

枚舉第一象限裏的一個點,剩下三個象限裏維護3個指針,就能找出來第3象限裏能和當前點組成矩形的點。

二四象限同理。

#include<bits/stdc++.h>
#define N 5005
#define ll long long
using namespace std;
int n;
struct node
{
    int x,y;
}a[N];
ll ans1,ans2,now;
int p[N];
bool cmp(int x,int y)
{
    return a[x].x<a[y].x;
}
int q1[N],q2[N],q3[N],q4[N],top[5];
int solve(int x)
{
    memset(top,0,sizeof(top));
    for(int i=1;i<=n;i++)
    {
        if(p[i]<x)
        {
            int op=1;
            int t=p[i];
            if(a[t].x<a[x].x&&a[t].y>a[x].y)op=2;
            if(a[t].x<a[x].x&&a[t].y<a[x].y)op=3;
            if(a[t].x>a[x].x&&a[t].y<a[x].y)op=4;
            if(op==1)if(!top[1]||a[t].y<a[q1[top[1]]].y)q1[++top[1]]=t;
          
            if(op==2)
            {
                while(top[2]&&a[t].y<a[q2[top[2]]].y)top[2]--;
                q2[++top[2]]=t;
            }
             
            if(op==3)
            {
                while(top[3]&&a[t].y>a[q3[top[3]]].y)top[3]--;
                q3[++top[3]]=t;
            }
             
            if(op==4)if(!top[4]||a[t].y>a[q4[top[4]]].y)q4[++top[4]]=t;
        }
    }
    int ans=top[1]+top[2]+top[3]+top[4];
    int p1=top[2],p2=0,p3=top[3]+1,p4=top[3];
    for(int i=1;i<=top[1];i++)
    {
        while(p1>=1&&a[q2[p1]].y>a[q1[i]].y)p1--;
         
        while(p2+1<=top[4]&&a[q4[p2+1]].x<a[q1[i]].x)p2++;
         
        while(p3-1>=1&&(!p1||a[q3[p3-1]].x>a[q2[p1]].x))p3--;
         
        while(p4>=1&&(p2!=0&&a[q4[p2]].y>a[q3[p4]].y))p4--;
         
        if(p4>=p3)ans-=p4-p3+1;
    }
     
    p1=top[1]+1,p2=0,p3=top[4]+1,p4=top[4];
    for(int i=1;i<=top[2];i++)
    {
        while(p1-1>=1&&a[q1[p1-1]].y<a[q2[i]].y)p1--;
         
        while(p2<=top[3]&&a[q3[p2]].x<a[q2[i]].x)p2++;
         
        while(p3-1>=1&&(p2==top[3]+1||a[q4[p3-1]].y>a[q3[p2]].y))p3--;
         
        while(p4>=1&&(p1!=top[1]+1&&a[q4[p4]].x>a[q1[p1]].x))p4--;
         
        if(p4>=p3)ans-=p4-p3+1;
    }
     
    return ans;
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%d%d",&a[i].x,&a[i].y);
    for(int i=1;i<=n;i++)p[i]=i;
    sort(p+1,p+n+1,cmp);
    for(int i=1;i<=n;i++)
    {
        now+=solve(i);
        if(i&1)ans1+=now;
        else ans2+=now;
    }
    printf("%lld %lld\n",ans1,ans2);
    return 0;
}

  

bzoj 1824: [JSOI2010]下棋問題