[USACO5.5] 矩形周长Picture

https://www.luogu.org/problemnew/show/P1856

1.每个矩形由两条横向边和两条纵向边组成.

2.对于横向边,按纵坐标排序。设当前讨论的边为 A [s , t]

如果 A 是某个矩形的靠下的边,在树中查询[s,t]区间中被覆盖的长度为x,那么加上这条边后将增加(t-s-x);

如果 A 是某个矩形的靠上的边,先删除它的对应边,再在树中查询[s,t]区间中被覆盖的长度为x,那么加上这条边后将增加(t-s-x);

3、对于纵向边,按横坐标排序,讨论方法与横向边相同。

注意建树方式是以单位线段为叶子节点

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <cmath>

#define LL long long

using namespace std;
const int MAXN = 2e4 + 5;
const int INF = 1e9;

int n,m,Ans = 0;

#define Max 10001

inline void read(int &x){
    x=0; int f=1; register char c = getchar();
    while(c>‘9‘||c<‘0‘){ if(c==‘-‘)f=-1; c=getchar(); }
    while(c>=‘0‘&&c<=‘9‘){ x=x*10+c-‘0‘; c=getchar(); } x*=f;
}

struct Seg_Ment{
    int s,t,id,p; // s、t线段端点 p是排序依据  id--排序之前的编号
    Seg_Ment(int a,int b,int c,int d):s(a),t(b),p(c),id(d){}
    Seg_Ment(){ s=t=p=id=0; }
    bool operator < (const Seg_Ment a) const {
        return p < a.p;
    }
}x[MAXN],y[MAXN];

int lazy[MAXN << 3],cnt[MAXN << 3],l,r;

inline void Push_Down(int u){
    int ls = u << 1 ,rs = u << 1|1;
    lazy[ls] += lazy[u],cnt[ls] += lazy[u],cnt[rs] += lazy[u],lazy[rs] += lazy[u];
    lazy[u] = 0;
}

void UpDate(int u,int L,int R,int Del){
    if(lazy[u]) Push_Down(u);
    if(l <= L && R <= r){
        cnt[u] += Del,lazy[u] += Del;
    }
    else if(L + 1 < R){
        int Mid = (L+R) >>1,ls = u<<1,rs = u<<1|1;
        if(l <= Mid && L <= r) UpDate(ls,L,Mid,Del);
        if(r >= Mid && l <= R) UpDate(rs,Mid,R,Del);
    }
}

int query(int u,int L,int R){
    if(lazy[u]) Push_Down(u);
    if(l <= L && R <= r && cnt[u] > 0) return R - L;
    if(L + 1 < R){
        int Mid = L+R >>1,a = 0,b = 0;
        if(l <= Mid) a = query(u<<1,L,Mid);
        if(r >= Mid) b = query(u<<1|1,Mid,R);
        return a + b;
    }
    return 0;
}

int main(int argc,char *argv[]){
    freopen("gg.out", "w", stdout);
    cin >> n;
    for(int i = 1; i <= n; i ++) {
        cout << i << ":" << " " << tan(i) << endl;
    }
    return 0;
    int x1,y1,xx,yy;
    read(n);
    for(int i=1; i<=n; ++i){
        read(x1),read(y1),read(xx),read(yy);
        x1 += Max,xx += Max,y1 += Max, yy += Max;
        x[i] = Seg_Ment(x1,xx,y1,i),y[i] = Seg_Ment(y1,yy,x1,i);
        x[i + n] = Seg_Ment(x1,xx,yy,i + n),y[i + n] = Seg_Ment(y1,yy,xx,i + n);
    }

    return 0;
    sort(x + 1,x + 2 * n + 1);
    sort(y + 1,y + 2 * n + 1);
    memset(lazy,0,sizeof lazy ); memset(cnt,0,sizeof cnt );
    for(int i=1; i<=n * 2; ++i){
        l = x[i].s, r = x[i].t;
        if(x[i].id <= n){
            Ans += abs(r - l - query(1,1,MAXN));
            UpDate(1,1,MAXN,1);
        }
        else {
            UpDate(1,1,MAXN,-1);
            Ans += abs(r - l - query(1,1,MAXN));
        }
    }
    memset(lazy,0,sizeof lazy ); memset(cnt,0,sizeof cnt );
    for(int i=1; i<=n * 2; ++i){
        l = y[i].s,r = y[i].t;
        if(y[i].id <= n){
            Ans += abs(r - l - query(1,1,MAXN));
            UpDate(1,1,MAXN,1);
        }
        else{
            UpDate(1,1,MAXN,-1);
            Ans += abs(r - l - query(1,1,MAXN));
        }
    }
    cout << Ans << endl;
    return 0;
}

原文地址:https://www.cnblogs.com/shandongs1/p/8406563.html

时间: 2024-10-30 01:01:14

[USACO5.5] 矩形周长Picture的相关文章

[线段树扫描线][USACO5.5]矩形周长Picture

墙上贴着许多形状相同的海报.照片.它们的边都是水平和垂直的.每个矩形图片可能部分或全部的覆盖了其他图片.所有矩形合并后的边长称为周长. 所有矩形的边界.所有矩形顶点的坐标都是整数. 输入文件的第一行是一个整数N(0<=N<5000),表示有多少个矩形.接下来N行给出了每一个矩形左下角坐标和右上角坐标(所有坐标的数值范围都在-10000到10000之间). 输出文件只有一个正整数,表示所有矩形的周长. 题解 线段树扫描线  https://www.luogu.org/problemnew/sol

USACO5.5 矩形周长 Picture | 扫描线 + 线段树

题目:Luogu 1856 扫描线,将矩形拆成两条边分别为 +1 和 -1,计算无重叠部分的长度. 由于 update 区间 [a, b] 和 [b, c] 时会把 b 加两次,所以统一转换成 [a,b),累加长度的时候再将右端点右移. 需要注意,在覆盖一条边时,不能直接累加边的长度,像下图: 在覆盖边 [1,4] 前,[3,4] 已经累加过了,所以此时应该累计的是 [1,4] 的长度减去已经覆盖过的长度,然后再把 [1,4] 覆盖上: 相应的,在删除 [1,4] 这条边时,累计的是删除 [1,

[USACO5.5]矩形周长Picture[扫描线+线段树]

题意:给出一些矩阵,求这些矩阵合并后外部(被包括在内部的不算)周长 端点-1这个是用点代替了边,区间内有几个点就代表区间长度是多少 #include <bits/stdc++.h> using namespace std; const int inf = 0x3f3f3f3f; inline void chmax(int &x, int y) {if (x < y) x = y;} inline void chmin(int &x, int y) {if (x >

luogu P1856 [USACO5.5]矩形周长Picture 扫描线 + 线段树

Code: #include<bits/stdc++.h> #define maxn 200007 #define inf 100005 using namespace std; void setIO(string s) { string in=s+".in"; freopen(in.c_str(),"r",stdin); } struct Edge { int l,r,h,flag; }edges[maxn]; int n; namespace tr

HDU 1828 Picture(矩形周长并)

HDU 1828 Picture 题目链接 题意:给定n个矩形,输出矩形周长并 思路:利用线段树去维护,分别从4个方向扫一次,每次多一段的时候,就查询该段未被覆盖的区间长度,然后周长就加上这个长度,4个方向都加完就是答案 代码: #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int N = 5005; int n; struct Rec { int

hdu1828 (Picture) &amp;poj 1177( Picture)&amp;sdibt 2390(5.5.1 Picture 矩形周长)(线段树+扫描)

题目地址:hdu1828 (Picture)  & poj 1177( Picture) & sdibt 2390(5.5.1 Picture 矩形周长) 题目大意: 给你N个矩形,求出N个矩形构成的周长. 解题思路: 线段数+扫描线. 推荐博客: POJ1177 Picture(线段树求轮廓周长) POJ 1177 Picture (线段树+离散化+扫描线) 详解 注意事项: 该题在求面积的基础上有了升级,多写了一个被调需要求出投影与Y轴有几段,不然样例会少算20,就是给出图形中间的小矩

poj 1177 Picture(扫描线+矩形周长并)

http://poj.org/problem?id=1177 求矩形的周长并,明确的一点是对于覆盖的边的长度忽略不计. 与求面积并类似,首先离散化,对矩形的每条横边从下往上扫描.扫描过程中要完成三个任务,更新相应的区间信息,求横边长,求竖边长. 节点信息: l,r:左右区间编号 cnt:表示该区间是否被完全覆盖.cnt > 0 表示完全覆盖,否则不完全覆盖. lp,rp:表示该区间的两个端点是否被覆盖,为1被覆盖,为0没被覆盖. num:该区间被覆盖的线段数目.例如区间[1,10],当更新[2,

HDU 1828 / POJ 1177 Picture --线段树求矩形周长并

题意:给n个矩形,求矩形周长并 解法:跟求矩形面积并差不多,不过线段树节点记录的为: len: 此区间线段长度 cover: 此区间是否被整个覆盖 lmark,rmark: 此区间左右端点是否被覆盖 num: 此区间分离开的线段的条数 重点在转移的地方,不难理解. 代码: #include <iostream> #include <cmath> #include <iostream> #include <cstdio> #include <cstrin

HDU 1828 扫描线(矩形周长并)

Picture Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 3310    Accepted Submission(s): 1723 Problem Description A number of rectangular posters, photographs and other pictures of the same shape