Picture
题意:求矩形面积并额轮廓长
解法:扫描线+离散化+线段树
做法:等于更新操作前后的tree[1].len差,做法这么巧妙实际我也不知道为什么。差不多的意思就是更新操作的cover变化长度就是新添加的段或者是删除掉的段,再加上最开始和最后的段更新。
两次根据离散去建立线段树进行统计,得到sum=平行y轴的长度+平行于x轴的长度
- 方法真的很巧妙,线段树博大精深
[代码]
- #include<iostream>
- #include<cstring>
- #include <algorithm>
- #include<cstdlib>
- #include<vector>
- #include<cmath>
- #include<stdlib.h>
- #include<iomanip>
- #include<list>
- #include<deque>
- #include<map>
- #include <stdio.h>
- #include <queue>
- #define maxn 50000+5
- #define inf 0x3f3f3f3f
- #define INF 0x3FFFFFFFFFFFFFFFLL
- #define rep(i,n) for(i=0;i<n;i++)
- #define reP(i,n) for(i=1;i<=n;i++)
- #define ull unsigned long long
- #define ll long long
- #define LL(x) x<<1
- #define RR(x) x<<1|1
- #define cle(a) memset(a,0,sizeof(a))
- using namespace std;
- int n;
- struct Line{//扫描线
- int ly,ry;
- int x,y;
- int flag;//出入操作标志
- }line[maxn];
- struct indata{//操作两次,所以先将数存入
- //存入读入数据
- int ip,x1,y1,x2,y2;
- indata(int a,int b,int c,int d){
- x1=a,y1=b,x2=c,y2=d;
- }
- indata(){
- }
- }dat[maxn];
- int hash[maxn];
- struct node{//线段树
- int l,r,flag;
- int lv,rv,len;
- int mid(){
- return (l+r)>>1;
- }
- }tree[maxn*4];
- void build(int rt,int l,int r)
- {//赋值操作
- tree[rt].l=l,tree[rt].r=r;
- tree[rt].lv=hash[l],tree[rt].rv=hash[r];
- tree[rt].flag=0,tree[rt].len=0;
- if(l+1==r)return;//叶子判断
- int mid=tree[rt].mid();
- build(LL(rt),l,mid),build(RR(rt),mid,r);
- }
- void doit(int x)//更新cover
- {
- if(tree[x].flag)tree[x].len=tree[x].rv-tree[x].lv;//被覆盖他的段最长
- else if(tree[x].l+1==tree[x].r)tree[x].len=0;//没有被覆盖并且是叶子
- else tree[x].len=tree[LL(x)].len+tree[RR(x)].len;//两个孩子的长度
- return;
- }
- void update(int rt,Line a){//更新操作
- if(a.ly==tree[rt].lv&&a.ry==tree[rt].rv){
- tree[rt].flag+=a.flag;
- doit(rt);return;
- }
- if(a.ry<=tree[LL(rt)].rv)update(LL(rt),a);
- else if(a.ly>=tree[RR(rt)].lv)update(RR(rt),a);
- else{
- Line temp=a;temp.ry=tree[LL(rt)].rv;update(LL(rt),temp);
- temp=a;temp.ly=tree[RR(rt)].lv;update(RR(rt),temp);
- }
- doit(rt);
- }
- void input()
- {
- int i;for(i=1;i<=n;i++){
- int x1,y1,x2,y2;
- scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
- dat[i]=indata(x1,y1,x2,y2);
- }
- }
- bool cmpy(Line a,Line b)
- {
- return a.x<b.x;
- }
- void output(Line a)
- {
- cout<<a.ly<<':'<<a.ry<<":"<<a.flag<<endl;
- }
- int main()
- {
- #ifndef ONLINE_JUDGE
- freopen("in.txt","r",stdin);
- //freopen("out.txt","w",stdout);
- #endif
- while(scanf("%d",&n)!=EOF){
- input();
- //先对平行y轴进行操作
- int i;
- for(i=1;i<=n;i++){
- line[2*i-1].ly=dat[i].y1,line[2*i-1].ry=dat[i].y2;
- line[2*i-1].x=dat[i].x1,line[2*i-1].flag=1;
- line[2*i].ly=dat[i].y1,line[2*i].ry=dat[i].y2;
- line[2*i].x=dat[i].x2,line[2*i].flag=-1;
- hash[2*i-1]=dat[i].y1,hash[2*i]=dat[i].y2;
- }
- int m=2*n;
- sort(line+1,line+1+m,cmpy),sort(hash+1,hash+m+1);
- build(1,1,m);update(1,line[1]);
- ll ans=0;
- int temp,tt;
- temp=tree[1].len;ans+=temp;
- for(i=2;i<=m;i++)
- {
- temp=tree[1].len;
- // output(line[i]);
- update(1,line[i]);
- tt=tree[1].len;
- ans+=abs(temp-tt);
- }
- for(i=1;i<=n;i++){
- line[2*i-1].ly=dat[i].x1,line[2*i-1].ry=dat[i].x2;
- line[2*i-1].x=dat[i].y1,line[2*i-1].flag=1;
- line[2*i].ly=dat[i].x1,line[2*i].ry=dat[i].x2;
- line[2*i].x=dat[i].y2,line[2*i].flag=-1;
- hash[2*i-1]=dat[i].x1,hash[2*i]=dat[i].x2;
- }
- sort(line+1,line+1+m,cmpy),sort(hash+1,hash+m+1);
- build(1,1,m);update(1,line[1]);
- temp=tree[1].len;ans+=temp;
- for(i=2;i<=m;i++){
- temp=tree[1].len;
- update(1,line[i]);tt=tree[1].len;
- ans+=abs(temp-tt);
- }
- printf("%I64d\n",ans);
- }
- return 0;
- }