我們可以先處理平行重疊的線段
以水平線段為例
對於$y$座標相同的線段,以左端點的$x$座標進行排序
這樣就可以找出對於某個$x$ (新線段的左端點),沿著這些線段最遠可以到多遠 (新線段的右端點) 了
於是,我們以一堆互不相交的水平線段取代了原本的,而不影響覆蓋面積
垂直線段也是一樣作法
實作請參考void MergeSegments(vector<pair<int,int> >&s)
可以發現,現在同一個點最多被覆蓋兩次 (水平線段+垂直線段)
因此可以直接套用「水平線段覆蓋面積+垂直線段覆蓋面積-兩者相交面積」
我們可以考慮對$y$離散化,然後掃描線從左到右掃
對於每個$x$座標
我們可以輕易地用$BIT$ ($Binary\ Indexed\ Tree$) 算出對於任何一個$x$的截面,水平線段的覆蓋數
對於每個存在垂直線段的$x$截面,我們只要將答案扣掉垂直線段覆蓋到的水平線段覆蓋數 ($BIT$裡面的一段區間),然後加上垂直線段的長度就好
可以套用大量的STL來實現上述過程,小心不要被一堆$first$和$second$搞混亂就好XD
時間複雜度:$O(N\log N)$
code:
#include<cstdio> #include<cassert> #include<map> #include<vector> #include<algorithm> using namespace std; typedef __int64 LL; const int INF=2147483647; void getmin(int &a,const int b){if(b<a)a=b;} void getmax(int &a,const int b){if(b>a)a=b;} int N; void MergeSegments(vector<pair<int,int> >&s) { assert(!s.empty()); sort(s.begin(),s.end()); pair<int,int>now=s[0]; vector<pair<int,int> >ans; for(const pair<int,int>&p:s) { if(now.second<p.first)ans.push_back(now),now=p; else getmax(now.second,p.second); } ans.push_back(now); s.clear(),ans.swap(s); } struct Bit { int n; vector<int>s; vector<LL>cnt; void clear(const int _n){n=_n;s.clear(),cnt.clear();s.resize(n,0),cnt.resize(n,0LL);} void Add(int i,const int v,const int ratio) { if(!ratio)return; assert(i<n&&(cnt[i]+=ratio)>=0); if(ratio<0){if(cnt[i])return;} if(ratio>0){if(cnt[i]>ratio)return;} while(i<n)s[i]+=(ratio<0?-v:v),i+=(i&(-i)); } int Query(int i) { int ans=0; while(i)ans+=s[i],i-=(i&(-i)); return ans; } }BIT; int Id(const vector<int>&y,const int val) { const int ans=lower_bound(y.begin(),y.end(),val)-y.begin(); assert(y[ans]==val); return ans; } LL Solve(const map<int,vector<pair<int,int> > >&mv,const map<int,vector<pair<int,int> > >&mh) { map<int,map<int,int> >endpoints; vector<int>y; for(const auto &it:mh) { y.push_back(it.first),y.push_back(it.first+1); for(const pair<int,int>&p:it.second) { endpoints[p.first][it.first]++,endpoints[p.second][it.first]--; } } for(const auto &it:mv)for(const pair<int,int>&p:it.second) { y.push_back(p.first),y.push_back(p.second); } sort(y.begin(),y.end()),y.resize(unique(y.begin(),y.end())-y.begin()); BIT.clear(y.size()); int ynow=-1000000000; LL ans=0LL; auto eps=endpoints.begin(); for(const auto &vsegs:mv) { for(;eps!=endpoints.end()&&eps->first<=vsegs.first;eps++) { ans+=(LL)((eps->first)-ynow)*BIT.Query((int)y.size()-1); ynow=eps->first; for(const auto &ep:eps->second)BIT.Add(Id(y,ep.first)+1,1,ep.second); } for(const pair<int,int>&vseg:vsegs.second) { ans-=BIT.Query(Id(y,vseg.second))-BIT.Query(Id(y,vseg.first)); ans+=vseg.second-vseg.first; } } for(;eps!=endpoints.end();eps++) { ans+=(LL)((eps->first)-ynow)*BIT.Query((int)y.size()-1); ynow=eps->first; for(const auto &ep:eps->second)BIT.Add(Id(y,ep.first)+1,1,ep.second); } assert(y.empty()||BIT.Query((int)y.size()-1)==0); return ans; } int main() { // freopen("in.txt","r",stdin); while(scanf("%d",&N)==1) { map<int,vector<pair<int,int> > >mv,mh; for(int i=0,x1,y1,x2,y2;i<N;i++) { scanf("%d%d%d%d",&x1,&y1,&x2,&y2); if(x1==x2)mv[x1].push_back(make_pair(min(y1,y2),max(y1,y2)+1)); else assert(y1==y2),mh[y1].push_back(make_pair(min(x1,x2),max(x1,x2)+1)); } for(auto &it:mv)MergeSegments(it.second); for(auto &it:mh)MergeSegments(it.second); printf("%I64d\n",Solve(mv,mh)); } return 0; }
沒有留言:
張貼留言
歡迎留言或問問題~
若您的留言中包含程式碼,請參考這篇
如果留言不見了請別慌,那是因為被google誤判成垃圾留言,小莫會盡快將其手動還原
注意:只有此網誌的成員可以留言。