1. 程式人生 > >BZOJ 3276 磁力 分塊

BZOJ 3276 磁力 分塊

慣例,傳送門:3276 磁力

然後就開講啦,分塊思維題……

1.首先要明白:這題的樸素做法是直接對石頭bfs

    但很快就能發現2.5*105的複雜度肯定是T到飛起的,於是考慮優化時間複雜度.

 

 

2.思考:怎樣才能對於每塊石頭只掃一遍呢?

    (響指)打標記!標記過的就不掃.

    But,真的好寫嗎?複雜度真的降了嗎???

    顯然沒有.

    考慮分塊,讓序列更好查詢.

    先按質量從小到大排成T塊[注意取每塊內部最後一個石的重量m作為該塊最大值,留下備用],在每塊內部再按距離從小到大重新排序.

    [技巧]因為吸引的中心只能是起始點,在讀入詢問時,將起始點作為0號石,對接下來的每個石直接算距離存起來,避免大量冗餘計算.

    接下來,就是最動人心魄魔改bfs啦!

 

 

3.魔改bfs

    0號石入隊,開始bfs.

    一般情況:對於每塊石頭i,從隊中取出,最終答案++,

        ①在分塊中都有第1~j-1塊的石頭質量全部小於等於i的吸力(用之前備用的塊最大重量比較),這些可以全部快速掃,具體過程後續.

        ②第j塊石頭中有0~塊長-1(數量不定)的石頭質量小於等於i的吸力,咱們將這些石頭樸素掃,具體過程後續.

        ③第j+1到T塊全都不符合條件,直接不掃.

    詳細過程:

    首先二分(lower_bound)找出j.

        ①快速掃:保證在本塊內且半徑符合條件,標記,入隊,指標不管是否標記過都++.

        ②樸素掃:先判重量條件,再判半徑條件,還要判在j塊內,標記,入隊,只要重量條件符合指標都++.

 

 

於是,這題就這麼華麗麗地做完啦!撒花!

 

 

 

 

 

 

 

 

 

 

 


 

 

等一下,真的完了?

事實上,我們在bfs時將起始點也作為一塊可抓的石頭,因此最終答案還應該--,輸出即可AC!

撒花!

 

 

 

 

 

 

 

 

 

 


 

 

真沒了,回去吧!

 

 

 

 

 

 

 

 

 

 

  1 //Written By Peter0701
  2 #include<bits/stdc++.h>
  3 using namespace std;
  4 typedef long long ll;
  5 int x,y,n,u,v,t,L[505],maxx[505],tot;
  6 bool vis[250005];
  7 queue<int> q;
  8 inline int read()
  9 {
 10     int ret=0,f=1;
 11     char ch=getchar();
 12     while(ch>'9'||ch<'0')
 13     {
 14         if(ch=='-')
 15             f=-1;
 16         ch=getchar();
 17     }
 18     while(ch<='9'&&ch>='0')
 19     {
 20         ret=(ret<<1)+(ret<<3)+ch-'0';
 21         ch=getchar();
 22     }
 23     return ret*f;
 24 }
 25 struct node
 26 {
 27     int m,p,r,pos;
 28     double dis;
 29 }a[250005];
 30 bool cmp1(node alp,node bet)
 31 {
 32     return alp.m<bet.m;
 33 }
 34 bool cmp2(node alp,node bet)
 35 {
 36     if(alp.pos==bet.pos)
 37         return alp.dis<bet.dis;
 38     else
 39         return alp.pos<bet.pos;
 40 }
 41 void bfs()
 42 {
 43     while(!q.empty())
 44     {
 45         int s=q.front();
 46         tot++;
 47         q.pop();
 48         int k=upper_bound(maxx+1,maxx+1+a[n].pos,a[s].p)-maxx;
 49         for(int i=1;i<=k-1;i++)
 50         {
 51             int &j=L[i];
 52             while(a[j].dis<=a[s].r&&j<=min(i*t,n))
 53             {
 54                 if(!vis[j])
 55                     q.push(j);
 56                 vis[j++]=true;
 57             }
 58         }
 59         int i=L[k];
 60         if(!i)
 61             continue;
 62         while(a[i].dis<=a[s].r&&i<=min(k*t,n))
 63         {
 64             if(a[i].m<=a[s].p&&!vis[i])
 65             {
 66                 vis[i]=true;
 67                 q.push(i);
 68             }
 69             i++;
 70         }
 71     }
 72 }
 73 int main()
 74 {
 75     x=read();
 76     y=read();
 77     a[0].p=read();
 78     a[0].r=read();
 79     n=read();
 80     for(int i=1;i<=n;i++)
 81     {
 82         u=read();
 83         v=read();
 84         a[i].m=read();
 85         a[i].p=read();
 86         a[i].r=read();
 87         a[i].dis=sqrt(ll(u-x)*ll(u-x)+ll(v-y)*ll(v-y));
 88     }
 89     sort(a+1,a+n+1,cmp1);
 90     t=sqrt(n);
 91     for(int i=1;i<=n;i++)
 92         a[i].pos=(i-1)/t+1;
 93     for(int i=1;i<=a[n].pos;i++)
 94     {
 95         L[i]=(i-1)*t+1;
 96         maxx[i]=a[min(n,i*t)].m;
 97     }
 98     sort(a+1,a+n+1,cmp2);
 99     q.push(0);
100     bfs();
101     printf("%d\n",tot-1);
102     return 0;
103 }
說了沒了你還來,這下被發現了吧