[CERC2017]Buffalo Barricades__CERC

來源:互聯網
上載者:User
思路

set+並查集+玄學亂搞……
一道對STL的靈活運用題……
這個我也是看了Claris大神的部落格才寫出來的(%%%)
好了廢話不多說,我們進入正題。
這道題其實就是求一個點為右上方能圍住多少點(廢話)
按照官方題解的思路,首先要用一個玄學掃描線維護。
既然要掃描線,那麼肯定首先排序啊。
按y軸從大到小排序,掃描從上往下。
好了現在我們拋開被圍的點,只注意柵欄的頂點。
首先,一個柵欄的頂點向左和下發出射線。
向下發出的射線在x軸上就是它本身的位置,只要在set中保留這個點就相當於儲存了這條射線。
那麼我們現在只考慮向左發出的射線。
若有下面兩個點:

這裡如果A加入的時間比D早,那麼最終形成的就是這樣:

如果A比D晚,則是這樣:

可以看出,在上面的第二種情況下,A點要在D加入時從set中刪去。(見代碼中的“注釋1”)
好了,這一種情況我們就解決了。
但是範例中3號點和4號點的情況呢。
可以看出,範例中是3號點包含4號點。
統計時,3號點的答案要加上4號點的答案。
但是,如果是1和3的情況,雖然3也包含1,但是並不需要把3號點加上1號點的答案。(“注釋5”)
那麼我們可以建立一個並查集。
在每次加入一個點的時候,記錄一個在它右側且比它的時間大的點;(見代碼中的“注釋2”)
最後倒序枚舉每一個點,用並查集維護,這個點的答案就是這個點所屬並查集的數量之和。(“注釋3”)
然後將這個點與插入時在他右側的點,加入一個並查集中。

最後一個問題:上面斜體字有啥用。
“倒序枚舉”,是由於在上面統計時我們已經把所有的點加入到整個圖中。
而現在需要分開統計,倒序刪去每一條邊,就相當於一個拓撲排序。(“注釋4”) 代碼

//STL有啥不好啦,代碼量短,如果手寫splay還要各種操作,STL多簡潔明了啊#include <cstdio>#include <set>#include <utility>#include <algorithm>const int maxn=300000;struct point{  int x,y,t;};typedef std::set<std::pair<int,int> > set_pair;typedef std::set<std::pair<int,int> >::iterator set_pair_iterator;set_pair s;int cnt[maxn+10],n,m,par[maxn+10],ans[maxn+10];point p[(maxn<<1)+10];struct union_find_set{  int fa[maxn+10];  int find(int x)  {    return fa[x]?fa[x]=find(fa[x]):x;  }  inline int merge(int x,int y)  {    x=find(x);    y=find(y);    if(x!=y)      {        fa[x]=y;        cnt[y]+=cnt[x];      }    return 0;  }};union_find_set f;bool cmp(const point &a,const point &b){  if(a.y==b.y)    {      return a.x<b.x;    }  return a.y>b.y;}int main(){  scanf("%d",&n);  for(register int i=1; i<=n; ++i)    {      scanf("%d%d",&p[i].x,&p[i].y);      p[i].x=(p[i].x<<1)-1;      p[i].y=(p[i].y<<1)-1;      p[i].t=0;    }  scanf("%d",&m);  for(register int i=1; i<=m; ++i)    {      scanf("%d%d",&p[n+i].x,&p[n+i].y);      p[n+i].x<<=1;      p[n+i].y<<=1;      p[n+i].t=i;    }  std::sort(p+1,p+n+m+1,cmp);  for(register int i=1; i<=n+m; ++i)    {      std::pair<int,int> q=std::make_pair(p[i].x,p[i].t);      if(p[i].t)        {          s.insert(q);          set_pair_iterator now=s.find(q);          if((++now)!=s.end())            {              par[p[i].t]=now->second;//注釋2:記錄在它右側的點            }          while(1)//注釋1:這個while迴圈就是在進行這個步驟            {              now=s.find(q);              if(now==s.begin())                {                  break;                }              if((--now)->second<p[i].t)                {                  break;                }              s.erase(now);            }        }      else        {          set_pair_iterator it=s.lower_bound(q);          if(it!=s.end())            {              ++cnt[it->second];            }        }    }  for(register int i=m; i; --i)//注釋3:這個for迴圈就是在進行這樣的步驟  //注釋4:注意倒序枚舉    {      ans[i]=cnt[f.find(i)];      if(par[i])        {          f.merge(i,par[i]);          //注釋5:這裡並沒有特殊處理出上面的情況          //因為如果par的時間大於i的時間,那麼加入同一併查集了並不影響結果        }    }  for(register int i=1; i<=m; ++i)    {      printf("%d\n",ans[i]);    }  return 0;}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.