luogu3875 [TJOI2010]被污染的河流

http://www.elijahqi.win/2018/01/02/luogu3875-tjoi2010%e8%a2%ab%e6%b1%a1%e6%9f%93%e7%9a%84%e6%b2%b3%e6%b5%81/
题目背景

有一座城市,城市里有许多条人工河,河流的流向都是水平或者竖直的。为了方便市民用水,政府将河流设计成网格状。在水平方向上和竖直方向上,相邻河流的距离都是1公里。河流围出许多格子,每个格子就是一个社区,社区里的居民可以到社区周边四条河段中的任意一处打水喝。
题目描述

郁闷的是,不久之后,有些不法商人修建了工厂,污染了河流。河边许多居民喝了被污染的水,生病了。政府派出专员小强调查污染情况。地理专家小强行动迅速,很快给出了污染分布。他给出了一张污染清单。清单列出了被污染的河段,所有能喝到该河段水的居民都有可能生病(河段的端点处忽略不计)。但是,笨笨的小强怎么也算不出具体会有多少个社区的居民会生病,所以,他请你来帮帮忙。

输入输出格式

输入格式:

输入文件的第一行是一个整数N,表示被污染的河段的数目。

接下来N行,每行4个整数x1,y1,x2,y2,表示被污染河段的起始位置和结束位置。每行输入的两个位置保证不重合,并且满足x1=x2或y1=y2

输出格式:

输出一个整数A,表示有A个社区的居民会喝到被污染的水。
输入输出样例

输入样例#1: 复制

3
1 3 4 3
6 7 6 3
4 6 7 6

输出样例#1: 复制

16

说明

对于10%的数据,1 ≤ x1,y1,x2,y2 ≤ 100,N ≤ 100;

对于30%的数据,1 ≤ x1,y1,x2,y2 ≤ 10000,N ≤ 100;

对于100%的数据,1 ≤ x1,y1,x2,y2 ≤ 100000,N ≤ 10000。

每个测试点时限1秒。

哇首先必膜icefox巨佬 在蒟蒻我苦苦思索 大佬直接秒出正解 这不矩形面积并嘛 强啊 %%这里写图片描述

顺带学习了下这种扫描线的写法 表示自己以前写的十分不好 不方便写代码 很麻烦 还是膜icefox吧
这里写图片描述

这题首先已经可以知道 方法就是扫描线做矩形面积并 那么 我是以横坐标排序 然后纵坐标线段树这样做的 首先我把每个矩形拆分成两个线 一个是左边的一个是右边的 注意 我扫描线我现在一共需要维护两种东西 1、我这区域被覆盖几次 2、我这区域被覆盖的长度是多少

那么只有在我区域被覆盖次数减没的时候我需要把区间覆盖的长度更改一下 注意 这个更改不是直接暴力的更改成0 而是更改成我子节点覆盖的一共有多少 此外update的时候 如果发现我当前这一层已经被完整的覆盖了 那么我就不从下一级更新上来了 画一画图就可以知道了 然后直接输出答案即可 另外这题 因为针对这个y也不是闭区间 所以我干脆给他变成这个左闭右开的形式方便统计答案


#include<cstdio>
#include<algorithm>
#define N 110000
#define ll long long
using namespace std;
inline char gc(){
    static char now[1<<16],*S,*T;
    if (T==S){T=(S=now)+fread(now,1,1<<16,stdin);if (T==S) return EOF;}
    return *S++;
}
inline int read(){
    int x=0;char ch=gc();
    while(ch<'0'||ch>'9') ch=gc();
    while(ch<='9'&&ch>='0'){x=x*10+ch-'0';ch=gc();}
    return x;
}
struct node{
    int x,y1,y2,op;
}line[N>>1];
struct node1{
    int left,right,v,len;
}tree[N<<2];
int num=0,n,root;ll ans; 
inline bool cmp(node a,node b){return a.x==b.x?a.op>b.op:a.x<b.x;}
inline void update(int x){
    if (tree[x].v) return;
    int l=tree[x].left,r=tree[x].right;
    tree[x].len=tree[l].len+tree[r].len;
}
inline void insert1(int x,int l,int r,int l1,int r1,int v){
    if (l1<=l&&r1>=r){tree[x].v+=v;if (tree[x].v) tree[x].len=r-l+1;else update(x);return;}
    int mid=l+r>>1;if (l1<=mid) insert1(tree[x].left,l,mid,l1,r1,v);
    if (r1>mid) insert1(tree[x].right,mid+1,r,l1,r1,v); update(x);
}
void build(int &x,int l,int r){
    x=++num;if (l==r) return;
    int mid=l+r>>1;build(tree[x].left,l,mid);build(tree[x].right,mid+1,r);
}
int main(){
    freopen("3875.in","r",stdin);
    n=read();int max1=0;
    for (int i=1;i<=n;++i){
        int x1=read(),y1=read(),x2=read(),y2=read();
         if (x1>x2) swap(x1,x2);if (y1>y2) swap(y1,y2);max1=max(max1,y2+1);
         if (x1==x2){
            line[++num].x=x1-1;line[num].y1=y1;line[num].y2=y2;line[num].op=1;
            line[++num].x=x2+1;line[num].y1=y1;line[num].y2=y2;line[num].op=0;
         }else{
            line[++num].x=x1;line[num].y1=y1-1;line[num].y2=y2+1;line[num].op=1;
            line[++num].x=x2;line[num].y1=y1-1;line[num].y2=y2+1;line[num].op=0;
         }
    }sort(line+1,line+num+1,cmp);num=0;build(root,0,max1);ll ans=0;
    for (int i=1;i<=n<<1;++i){
        ans+=(ll)tree[root].len*(line[i].x-line[i-1].x);
        insert1(root,0,max1,line[i].y1,line[i].y2-1,line[i].op?1:-1);
    }printf("%lld\n",ans);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值