Luogu P1856 [USACO5.5】写真矩形境界

走査線セグメントツリー+

走査線の古典的な問題

最初の考えは、二つの辺の両側上下及び横長方形で構成されています

水平エッジが考える、第1の垂直エッジを考慮し、二つの理由に分割されています

第1の横側を考えてみましょう

図2の矩形横断エッジは今や垂直側面を残し、拭き取りされる、平面は3つの領域に分割され

コード内に実装された場合、左から右エンドポイントに記録されていてもよいです

 

今走査線に対して横方向エッジと平行に下から上に掃引されていることを想像します

長方形の底部を掃引する場合、矩形断面のこれらのストリップは、下部カバーを含みます

長方形の上側を掃引する場合、矩形断面のこれらのストリップは、上部サイドカバーが取り外さ含みます

したがって、これらの領域のセグメントツリーのメンテナンス間隔の確立は、これらが被覆されているかどうかを、垂直ラインに分割され

 

そのような矩形状の底の底のような、広範囲2,3を網羅

それでは、どのように統計的な答え

間隔の全長のメンテナンスをカバーする現在のツリーラインの絶対値 - 答えは間隔被覆の合計の長さの最後のセグメントツリー維持であります

、最後の2を覆う、第二の側を走査するために、上記に示した3として、その範囲に上昇させます

次いで、この周波数範囲内のツリーラインは完全なカバレッジを維持するために、長さをカバーすることができます

#include <iostream>
#include <algorithm>
#include <map>
#include <cstdio>
#define inf (int)1e9
using namespace std;
int n,w,last,ans;
struct node
{
    int a,b,c,d;
}p[5100];
struct tree
{
    int l,r,sum;
    int len;
}sh[100000];
struct edge
{
    int l,r,num,kind;
}a[11000];
bool cmp(edge a,edge b)
{
    return (a.num<b.num || (a.num==b.num && a.kind>b.kind));//注意如果同一高度的话,先处理下边的
}
void pushup(int x)
{
    if (sh[x].sum>0)//如果当前被完全覆盖,那么当前区间被覆盖的长度为r-l+1
      sh[x].len=sh[x].r-sh[x].l+1;
    else
    if (sh[x].l==sh[x].r)//叶子结点
      sh[x].len=0;
    else
      sh[x].len=sh[x+x].len+sh[x+x+1].len;//一般情况
}
void build(int x,int ll,int rr)
{
    sh[x].l=ll;
    sh[x].r=rr;
    sh[x].sum=sh[x].len=0;
    if (ll==rr)
      return;
    int mid;
    mid=(ll+rr)>>1;
    build(x+x,ll,mid);
    build(x+x+1,mid+1,rr);
}
void change(int x,int ll,int rr,int v)
{
    if (sh[x].l>=ll && sh[x].r<=rr)
    {
        sh[x].sum+=v;
        pushup(x);
        return;
    }
    int mid;
    mid=(sh[x].l+sh[x].r)>>1;
    if (ll<=mid)
      change(x+x,ll,rr,v);
    if (rr>mid)
      change(x+x+1,ll,rr,v);
    pushup(x);
}
int main()
{
    scanf("%d",&n);
    for (int i=1;i<=n;i++)
      scanf("%d%d%d%d",&p[i].a,&p[i].b,&p[i].c,&p[i].d);
    for (int i=1;i<=n;i++)//记录前扫描线要扫到的边
    {
        w++;
        a[w].l=p[i].a;a[w].r=p[i].c;
        a[w].kind=1;a[w].num=p[i].b;//下边
        w++;
        a[w].l=p[i].a;a[w].r=p[i].c;
        a[w].kind=-1;a[w].num=p[i].d;//上边
    }
    build(1,-10000,10000);
    sort(a+1,a+1+w,cmp);
    last=0;//上一次答案
    for (int i=1;i<=w;i++)
    {
        change(1,a[i].l,a[i].r-1,a[i].kind);
        ans+=abs(last-sh[1].len);
        last=sh[1].len;
    }
    w=0;//处理竖边
    for (int i=1;i<=n;i++)
    {
        w++;
        a[w].l=p[i].b;a[w].r=p[i].d;
        a[w].kind=1;a[w].num=p[i].a;
        w++;
        a[w].l=p[i].b;a[w].r=p[i].d;
        a[w].kind=-1;a[w].num=p[i].c;
    }
    build(1,-10000,10000);
    sort(a+1,a+1+w,cmp);
    last=0;
    for (int i=1;i<=w;i++)
    {
        change(1,a[i].l,a[i].r-1,a[i].kind);
        ans+=abs(last-sh[1].len);
        last=sh[1].len;
    }
    printf("%d\n",ans);
}

 

おすすめ

転載: www.cnblogs.com/huangchenyan/p/11329446.html