【xsy2305】嘍 計算幾何

UPD:這個作法被hack了node

題目大意:給你$n$個紅點和$m$個黑點,問你至少須要保留多少個黑點,才能用由黑點組成的凸包包住全部紅點。c++

數據範圍:$n≤10^5$,$m≤500$oop

 

首先,咱們將紅點和黑點丟到一塊兒,求一個凸包。凸包上的點能用黑點就用黑點,不然才用紅點。ui

全部重點,三點共線的點,都會被刪除。spa

若是求出的凸包上有紅點,那麼顯然是包不住的,直接輸出-1便可。code

咱們將在凸包上的黑點找出。blog

 

設$nxt[i]$表示凸包上第$i$號節點,能在順時針方向上刪除多少個凸包上的點,使得凸包依然能包含住所有的紅點。it

若是咱們求出了這個東西,咱們顯然能夠在$O(m)$的時間複雜度內,求出最少須要多少個點。class

 

考慮如何求$nxt[i]$hack

咱們對於由$i$和$i+nxt[i]$構成的連線,若是是合法的,那麼顯然要知足凸包外側沒有任何點。

咱們能夠對全部紅點,都用叉積判一遍就能夠了。

更新$nxt[i]$的過程能夠用相似旋轉卡殼的方式來搞,單次均攤是$O(n)$的。

(我場上$sb$了竟然在求凸包,雖然也能夠判,可是它T了)

這麼搞時間複雜度是$O(nm)$的,實際上跑得飛快。

時間複雜度爲$O((n+m)\log\ (n+m)+nm)$

 

 1 #include<bits/stdc++.h>
 2 #define L long long
 3 #define M 110000
 4 #define INF 19890604
 5 using namespace std;
 6 
 7 struct node{
 8     L x,y;int type;
 9     void rd(int Type){type=Type; scanf("%lld%lld",&x,&y);}
10     node(){x=y=type=0;}
11     node(L X,L Y,int Type){x=X; y=Y; type=Type;}
12     friend node operator +(node a,node b){return node(a.x+b.x,a.y+b.y,0);}
13     friend node operator -(node a,node b){return node(a.x-b.x,a.y-b.y,0);}
14     friend L operator *(node a,node b){return a.x*b.y-a.y*b.x;}
15     friend bool operator ==(node a,node b){return a.x==b.x&&a.y==b.y;}
16 }a[M],s[M],b[505],all[M],bas=node(0,1e9,0);
17 int n,m,cnt=0,nm=0;
18 
19 bool cmp(node x,node y){
20     if(x.x==y.x&&x.y==y.y) return x.type<y.type;
21     return (x-bas)*(y-bas)>0;
22 }
23 void build(){
24     for(int i=1;i<=nm;i++) if(all[1].y>all[i].y) swap(all[1],all[i]);
25     bas=all[1]; sort(all+2,all+nm+1,cmp);
26     for(int i=1;i<=nm;i++){
27         while(cnt>1&&(s[cnt]-s[cnt-1])*(all[i]-s[cnt-1])<=0)
28         cnt--;
29         if(cnt>0&&s[cnt]==all[i]) cnt--;
30         s[++cnt]=all[i];
31     }
32 }
33 int nxt[M]={0},vis[M]={0};
34 int dfs(int x,int dep){
35     if(vis[x]) return printf("%d\n",dep-vis[x]);
36     vis[x]=dep;
37     dfs(nxt[x],dep+1);
38 }
39 
40 int main(){
41     scanf("%d%d",&n,&m);
42     for(int i=1;i<=n;i++) a[i].rd(1),all[++nm]=a[i];
43     for(int i=1;i<=m;i++) b[i].rd(2),all[++nm]=b[i];
44     build();
45     for(int i=1;i<=cnt;i++) if(s[i].type==1) return printf("-1\n");
46     if(cnt==1) return printf("1\n");
47     memset(b,0,sizeof(b)); m=cnt;
48     for(int i=1;i<=m;i++) b[i]=b[i+cnt]=s[i];
49     for(int i=1,j=1;i<=m;i++){
50         while(1){
51             if(j==i) j++;
52             for(int k=1;k<=n;k++)
53             if((a[k]-b[i])*(b[j]-b[i])>0)
54             goto loop;
55             j++;
56         }
57         loop:;
58         nxt[i]=(j-2+m)%m+1;
59     }
60     dfs(1,1);
61 }
相關文章
相關標籤/搜索