POJ1177 Picture (线段树+扫描线)

本题求周长,其实思路与面积完全相似

离散化+扫描线,本题甚至可以不用离散化,因为数据范围并不是特别大

我们能想到的暴力就是先算一遍横的,再算一遍竖的,我不知道这样能不能过,或许可以

但是我们发现其实可以在求竖线的时候顺便把横线求了,因为一条横线的长度永远是相邻x的差值

我们只需要考虑两个相邻的x有几条线,这个时候,我们可以在线段树中维护一个num表示有几条不连续的竖线,通过这样就可以算出横线的个数为2*num

但是我们还要维护一个ls和一个rs,表示我这个区间的左端和右端有没有覆盖,考虑这个是因为在更新父节点的时候会产生冲突,我们举个例子

左儿子是1-3,右儿子是4-6,我们假设每个儿子里面都有一条不连续的线,也就是说1-3和4-6都被覆盖了,那么在连续的时候,如果左儿子的rs和右儿子的ls都是1,那么其实这是一条连续的区间,而不是1+1=2;

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<map> 
#include<vector> 
using namespace std;
typedef  long long ll;
const int N=5e5+10;
const int inf=0x3f3f3f3f;
struct node{
    int l,r;
    int cnt;
    int len;
    int num;
    int ls;
    int rs;
}tr[N];
struct qi{
    int x;
    int y1;
    int y2;
    int k;
    bool operator <(const qi&t){
        return x<t.x; 
    }    
}q[N];
vector<int> num;
int find(int x){
    return lower_bound(num.begin(),num.end(),x)-num.begin()+1;
}
void build(int u,int l,int r){
    if(l==r){
        tr[u].l=tr[u].r=l;
    }
    else{
        tr[u].l=l;
        tr[u].r=r;
        int mid=l+r>>1;
        build(u<<1,l,mid);
        build(u<<1|1,mid+1,r);
    } 
}
void pushup(int u){
    if(tr[u].cnt){
        tr[u].len=num[tr[u].r]-num[tr[u].l-1];
        tr[u].ls=tr[u].rs=1;
        tr[u].num=1;
    }
    else if(tr[u].l==tr[u].r){
        tr[u].len=0;
        tr[u].num=0;
        tr[u].ls=tr[u].rs=0;
    }
    else{
        tr[u].len=tr[u<<1].len+tr[u<<1|1].len;
        tr[u].num=tr[u<<1].num+tr[u<<1|1].num;
        tr[u].ls=tr[u<<1].ls,tr[u].rs=tr[u<<1|1].rs;
        if(tr[u<<1].rs==1&&tr[u<<1|1].ls==1)
        tr[u].num-=1; 
    }
}
void modify(int u,int l,int r,int x){
    if(tr[u].l>=l&&tr[u].r<=r){
        tr[u].cnt+=x;
        pushup(u);
        return ;
    }
    int mid=tr[u].l+tr[u].r>>1;
    if(l<=mid)
    modify(u<<1,l,r,x);
    if(r>mid)
    modify(u<<1|1,l,r,x);
    pushup(u);
}
int main(){
    int n;
    cin>>n;
    int i;
    int idx=1;
    for(i=1;i<=n;i++){
        int x1,x2,y1,y2;
        scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
        q[idx].x=x1,q[idx].y1=y1,q[idx].y2=y2,q[idx].k=1;
        idx++;
        q[idx].x=x2,q[idx].y1=y1,q[idx].y2=y2,q[idx].k=-1;
        idx++;
        num.push_back(y1);
        num.push_back(y2);
    }
    sort(q+1,q+1+idx);
    sort(num.begin(),num.end());
    num.erase(unique(num.begin(),num.end()),num.end());
    int tmp=0;
    int res=0;
    build(1,1,num.size()-1);
    for(i=1;i<=idx;i++){
        tmp=tr[1].len;
        if(i>=2){
            res+=2*tr[1].num*(q[i].x-q[i-1].x);
        }
        modify(1,find(q[i].y1),find(q[i].y2)-1,q[i].k);
        res+=abs(tr[1].len-tmp);
    }
    cout<<res<<endl;
}
View Code
原文地址:https://www.cnblogs.com/ctyakwf/p/12331928.html