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;
- }