這還是個被我咕了N久的玩意
Minkowski和是一個奇怪的玩意
他長這樣
$S={a+b \| a \in A , b \in B}$
AB可以是點集也可是向量集(顯然)
他可以處理一些奇怪的東西
比如說我們來看這個題
你發現它要求的就是判斷向量是否存在於A-B的Minkowski和里
那么你套上板子就做完了
好了你大概了解了Minkowski和是什么
我們現在來學怎么寫
我們根據直觀理解 Minkowski上的點一定是點集構成的凸包上的點
於是我們暴力求出所有點再進行一次求凸包就做完了 復雜度是 O(|A|*|B|)
它看起來就不是很優 肯定可以優化
我們發現很好的性質 凸包上的點它的斜率是單調的 所以顯然可以TwoPointers優化
我們直接觀察哪一個在外面拓展就可以了
代碼實現扔這里了

//Love and Freedom. #include<algorithm> #include<cmath> #include<cstring> #include<cstdio> #define inf 20021225 #define ll long long #define db double #define eps 1e-8 #define N 200010 using namespace std; int read() { int f=1,s=0; char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-') f=-1; ch=getchar();} while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar(); return f*s; } struct poi { db x,y; poi(){} poi(db _x,db _y){x=_x,y=_y;} }; typedef poi vec; vec operator+(vec a,vec b){return vec(a.x+b.x,a.y+b.y);} vec operator-(vec a,vec b){return vec(a.x-b.x,a.y-b.y);} vec operator*(vec a,db b){return vec(a.x*b,a.y*b);} vec operator/(vec a,db b){return vec(a.x/b,a.y/b);} db cross(vec a,vec b){return a.x*b.y-a.y*b.x;} db dot(vec a){return a.x*a.x+a.y*a.y;} db len(vec a){return sqrt(dot(a));} db dis(poi a,poi b){return len(b-a);} poi p0; int dcmp(db x){return x>eps?1:x<-eps?-1:0;} bool cmp(poi p1,poi p2){return dcmp(cross(p1-p0,p2-p0))==1||(dcmp(cross(p1-p0,p2-p0))==0&&dis(p0,p1)<dis(p0,p2));} int gethull(poi *p,poi *h,int n) { p0=poi{1e18,1e18}; int id=0; for(int i=1;i<=n;i++) if(dcmp(p[i].x-p0.x)<0||(dcmp(p[i].x-p0.x)==0&&dcmp(p[i].y-p0.y)<0)) id=i,p0=p[i]; swap(p[1],p[id]); sort(p+2,p+n+1,cmp); int top=2; h[1]=p[1],h[2]=p[2]; for(int i=3;i<=n;i++) { while(top>2&&dcmp(cross(p[i]-h[top-1],h[top]-h[top-1]))>=0) top--; h[++top]=p[i]; } return top; } poi A[N],B[N],p[N],C[N]; int na,nb,nc; void minkowski() { A[na+1]=A[1],B[nb+1]=B[1]; C[nc=1]=A[1]+B[1]; int i=1,j=1; while(i<=na&&j<=nb) { vec v1=A[i+1]+B[j]-C[nc],v2=A[i]+B[j+1]-C[nc]; if(dcmp(cross(v1,v2))>=0) C[++nc]=A[i+1]+B[j],i++; else C[++nc]=A[i]+B[j+1],j++; } while(i<=na) C[++nc]=A[i]+B[j],i++; while(j<=nb) C[++nc]=A[i]+B[j],j++; } bool check(poi w) { if((dcmp(cross(w-C[1],C[nc]-C[1]))==0&&dis(C[nc],C[1])>=dis(C[1],w))||(dcmp(cross(w-C[1],C[2]-C[1]))==0 && dis(C[1],w)<=dis(C[2],C[1]))) return 1; int l=2,r=nc,ans=0; while(l<=r) { int mid=l+r>>1; poi p1=C[mid]; if(dcmp(cross(p1-C[1],w-C[1]))>=0) l=mid+1,ans=mid; else r=mid-1; } if(ans==nc||!ans) return 0; poi p1=C[ans],p2=C[ans+1]; if(dcmp(cross(p1-w,p2-w))>=0) return 1; return 0; } int main() { int n1=read(),n2=read(),q=read(); for(int i=1;i<=n1;i++) p[i].x=read(),p[i].y=read(); na=gethull(p,A,n1); for(int i=1;i<=n2;i++) p[i].x=-read(),p[i].y=-read(); nb=gethull(p,B,n2); minkowski(); while(q--) { poi w; w.x=read(),w.y=read(); printf("%d\n",check(w)); } return 0; }
注:1.求點是否在凸包內可以直接三角剖分以后二分在哪個極角區間內即可 2.至於為什么我想錘爆我自己的狗頭呢 因為我的cmp寫了dcmp>1調了一個世紀xtbl
另一道題
N校聯考的題
(題面好像沒法放/px)
就是我們首先猜結論 對於奇數和偶數的答案分別是凸的 那么考慮維護奇偶正負共四個凸的答案
我們分治去做 考慮如何合並
由於是凸的所以差分單調 那么我們就可以TwoPointers優化
然后求完答案繼續維護差分數組
(這個玩意貌似還叫做分治max卷積/px)
發現這個過程其實也是在求Minkowski和
我的代碼是展開討論寫的 於是它賊快但是賊長(

//Love and Freedom. #include<algorithm> #include<cmath> #include<cstring> #include<cstdio> #define inf (ll)(1e18) #define ll long long #define N 500010 using namespace std; int read() { int f=1,s=0; char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-') f=-1; ch=getchar();} while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar(); return f*s; } ll f[N][2],d[N][2],tmp[N][2],a[N]; void solve(int l,int r) { if(l==r){f[l][0]=a[l],f[l][1]=a[l]; d[l][0]=a[l],d[l][1]=a[l]; return;} int mid=l+r>>1; solve(l,mid); solve(mid+1,r); int it1,it2; ll val; for(int i=0;i<=r-l+1;i++) tmp[i][0]=-inf,tmp[i][1]=inf; it1=l+1,it2=mid+1; val=d[l][0]; for(int i=1;i<=r-l+1;i+=2) // odd l odd+ r even- { tmp[i][0]=max(tmp[i][0],val); if(it2>r-1 && it1>mid-1) break; if(it2>r-1 || (it1<=mid-1&&d[it1][0]+d[it1+1][0]>-d[it2][1]-d[it2+1][1])) val+=d[it1][0]+d[it1+1][0],it1+=2; else val-=d[it2][1]+d[it2+1][1],it2+=2; } it1=l,it2=mid+2,val=d[mid+1][0];// printf("%lld\n",val); for(int i=1;i<=r-l+1;i+=2) // odd l even+ r odd+ { tmp[i][0]=max(tmp[i][0],val); if(it2>r-1 && it1>mid-1) break; if(it2>r-1 || (it1<=mid-1&&d[it1][0]+d[it1+1][0]>d[it2][0]+d[it2+1][0])) val+=d[it1][0]+d[it1+1][0],it1+=2; else val+=d[it2][0]+d[it2+1][0],it2+=2; } it1=l+1,it2=mid+2,val=d[l][0]-d[mid+1][1]; for(int i=2;i<=r-l+1;i+=2) // even l odd+ r odd- { tmp[i][0]=max(tmp[i][0],val);//printf("%d %d %d %lld\n",i,it1,it2,val);// printf("%lld\n",val); if(it2>r-1 && it1>mid-1) break; if(it2>r-1 || (it1<=mid-1&&d[it1][0]+d[it1+1][0]>-d[it2][1]-d[it2+1][1])) val+=d[it1][0]+d[it1+1][0],it1+=2; else val-=d[it2][1]+d[it2+1][1],it2+=2; } it1=l,it2=mid+1,val=0; for(int i=0;i<=r-l+1;i+=2) // even l even+ r even+ { tmp[i][0]=max(tmp[i][0],val); if(it2>r-1 && it1>mid-1) break; if(it2>r-1 || (it1<=mid-1&&d[it1][0]+d[it1+1][0]>d[it2][0]+d[it2+1][0])) val+=d[it1][0]+d[it1+1][0],it1+=2; else val+=d[it2][0]+d[it2+1][0],it2+=2; } it1=l+1,it2=mid+1; val=d[l][1]; for(int i=1;i<=r-l+1;i+=2) // odd l odd+ r even- { tmp[i][1]=min(tmp[i][1],val); if(it2>r-1 && it1>mid-1) break; if(it2>r-1 || (it1<=mid-1&&d[it1][1]+d[it1+1][1]<-d[it2][0]-d[it2+1][0])) val+=d[it1][1]+d[it1+1][1],it1+=2; else val-=d[it2][0]+d[it2+1][0],it2+=2; } it1=l,it2=mid+2,val=d[mid+1][1]; for(int i=1;i<=r-l+1;i+=2) // odd l even+ r odd+ { tmp[i][1]=min(tmp[i][1],val); if(it2>r-1 && it1>mid-1) break; if(it2>r-1 || (it1<=mid-1&&d[it1][1]+d[it1+1][1]<d[it2][1]+d[it2+1][1])) val+=d[it1][1]+d[it1+1][1],it1+=2; else val+=d[it2][1]+d[it2+1][1],it2+=2; } it1=l+1,it2=mid+2,val=d[l][1]-d[mid+1][0]; for(int i=2;i<=r-l+1;i+=2) // even l odd+ r odd- { tmp[i][1]=min(tmp[i][1],val); if(it2>r-1 && it1>mid-1) break; if(it2>r-1 || (it1<=mid-1&&d[it1][1]+d[it1+1][1]<-d[it2][0]-d[it2+1][0])) val+=d[it1][1]+d[it1+1][1],it1+=2; else val-=d[it2][0]+d[it2+1][0],it2+=2; } it1=l,it2=mid+1,val=0; for(int i=0;i<=r-l+1;i+=2) // even l even+ r even+ { tmp[i][1]=min(tmp[i][1],val); if(it2>r-1 && it1>mid-1) break; if(it2>r-1 || (it1<=mid-1&&d[it1][1]+d[it1+1][1]<d[it2][1]+d[it2+1][1])) val+=d[it1][1]+d[it1+1][1],it1+=2; else val+=d[it2][1]+d[it2+1][1],it2+=2; } //printf("%d %d\n",l,r); for(int i=1;i<=r-l+1;i++) f[l+i-1][0]=tmp[i][0], f[l+i-1][1]=tmp[i][1]; //puts(""); d[l][0]=f[l][0],d[l][1]=f[l][1]; for(int i=l+1;i<=r;i++) d[i][0]=f[i][0]-f[i-1][0], d[i][1]=f[i][1]-f[i-1][1]; } int main() { int n=read(); for(int i=1;i<=n;i++) a[i]=read(); solve(1,n); for(int i=1;i<=n;i++) printf("%lld ",f[i][0]); return 0; }