[TopCoder12693]EnclosingTriangle
XXVIII.[TopCoder12693]EnclosingTriangle
经典套路是固定一个点,求出所有合法的剩余两个点。
为了方便,我们将环状的图形拆开,拆成 个点。然后,我们枚举一个点 明显发现,剩下两个点必定位于 两侧的一端区间内,不妨设一半是 ,另一半是 。此部分可以通过求出当前点与全部二十个点间的向量中倾角最大以及最小的两个,并且求出它们与正方形的交点并取整得到,复杂度 。
然后,考虑我们枚举第一个点 。则第二个点必定在 中,第三个点必在 中(因为要保证三个点递增)。于是,我们用two-pointers维护所有合法的第二个点 ,并用线段树维护所有这样的 的 上的带权和。之后,询问第三个点可能在的位置的带权和即可。复杂度 。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const double eps=1e-10;
int cmp(double x){
if(x>eps)return 1;
if(x<-eps)return -1;
return 0;
}
class EnclosingTriangle{
private:
int n,m,L[400100],R[400100],N;
struct Vector{
double x,y;
Vector(){}
Vector(double X,double Y){x=X,y=Y;}
friend Vector operator +(const Vector &u,const Vector &v){return Vector(u.x+v.x,u.y+v.y);}
friend Vector operator -(const Vector &u,const Vector &v){return Vector(u.x-v.x,u.y-v.y);}
friend Vector operator *(const Vector &u,const double &v){return Vector(u.x*v,u.y*v);}
friend Vector operator /(const Vector &u,const double &v){return Vector(u.x/v,u.y/v);}
friend double operator &(const Vector &u,const Vector &v){return u.x*v.y-u.y*v.x;}//cross times
friend double operator |(const Vector &u,const Vector &v){return u.x*v.x+u.y*v.y;}//point times
double operator ~()const{return sqrt(x*x+y*y);}//the modulo of a vector
double operator !()const{return atan2(y,x);}//the angle of a vector
void print(){printf("(%lf,%lf)",x,y);}
}p[30];
typedef Vector Point;
struct Line{
Point x,y;
Vector z;
Line(){}
Line(Point X,Point Y){x=X,y=Y,z=Y-X;}
friend Point operator &(const Line &u,const Line &v){return u.x+u.z*((v.z&(u.x-v.x))/(u.z&v.z));}
}bd[4];
typedef Line Segment;
int code(int x,int y){//code a point into an identification
if(y==0)return x;
if(x==m)return y+m;
if(y==m)return 3*m-x;
if(x==0)return 4*m-y;
}
int side(int x,int y){//find the side of a point
int ret=0;
if(y==0)ret|=1;
if(x==m)ret|=2;
if(y==m)ret|=4;
if(x==0)ret|=8;
return ret;
}
Point deco(int id){//deco an identification into a point
(id+=N)%=N;
if(id<m)return Point(id,0);
if(id<2*m)return Point(m,id-m);
if(id<3*m)return Point(3*m-id,m);
if(id<4*m)return Point(0,4*m-id);
}
int Crossover(Line l,int tp,int rd){//rd=1:round to maximal; rd=-1:round to minimal
if(!cmp(l.z&bd[tp].z))return -1;//two lines parallel
Point i=l&bd[tp];
if(cmp(i.x-m)==1||cmp(i.x)==-1||cmp(i.y-m)==1||cmp(i.y)==-1)return -1;//outside the boundary
int u,v;
if(tp==0){
u=i.x,v=u+1;
if(cmp(u-i.x)==0)return code(u,0);//coincide.
if(cmp(v-i.x)==0)return code(v,0);
return rd==1?code(v,0):code(u,0);
}
if(tp==1){
u=i.y,v=u+1;
if(cmp(u-i.y)==0)return code(m,u);
if(cmp(v-i.y)==0)return code(m,v);
return rd==1?code(m,v):code(m,u);
}
if(tp==2){
v=i.x,u=v+1;
if(cmp(u-i.x)==0)return code(u,m);
if(cmp(v-i.x)==0)return code(v,m);
return rd==1?code(v,m):code(u,m);
}
if(tp==3){
v=i.y,u=v+1;
if(cmp(u-i.y)==0)return code(0,u);
if(cmp(v-i.y)==0)return code(0,v);
return rd==1?code(0,v):code(0,u);
}
}
int findlimit(Line l,int rd,int ban){
for(int i=0;i<4;i++)if(!(ban&(1<<i))){
int tmp=Crossover(l,i,rd);
// printf("%d:%d\n",i,tmp);
if(tmp!=-1)return tmp;
}
}
#define lson x<<1
#define rson x<<1|1
#define mid ((l+r)>>1)
struct SegTree{int tag;ll sum;}seg[1001000];
void ADD(int x,int y,int l,int r){seg[x].sum+=1ll*(r-l+1)*y,seg[x].tag+=y;}
void pushup(int x){seg[x].sum=seg[lson].sum+seg[rson].sum;}
void pushdown(int x,int l,int r){ADD(lson,seg[x].tag,l,mid),ADD(rson,seg[x].tag,mid+1,r),seg[x].tag=0;}
void modify(int x,int l,int r,int L,int R,int val){
if(l>R||r<L)return;
if(L<=l&&r<=R){ADD(x,val,l,r);return;}
pushdown(x,l,r),modify(lson,l,mid,L,R,val),modify(rson,mid+1,r,L,R,val),pushup(x);
}
ll query(int x,int l,int r,int L,int R){
if(l>R||r<L)return 0;
if(L<=l&&r<=R)return seg[x].sum;
pushdown(x,l,r);return query(lson,l,mid,L,R)+query(rson,mid+1,r,L,R);
}
void modify(int x,int val){modify(1,0,N-1,x+1,R[x]<x?N-1:R[x],val);}
public:
ll getNumber(int M,vector<int>X,vector<int>Y){
m=M,n=X.size(),N=4*M;
bd[0]=Line(Vector(0,0),Vector(m,0));
bd[1]=Line(Vector(m,0),Vector(m,m));
bd[2]=Line(Vector(m,m),Vector(0,m));
bd[3]=Line(Vector(0,m),Vector(0,0));
for(int i=0;i<n;i++)p[i]=Vector(X[i],Y[i]);
for(int i=0;i<4*m;i++){
Point q=deco(i),mn=p[0],mx=p[0];
for(int j=1;j<n;j++){
if(cmp((p[j]-q)&(mn-q))==-1)mn=p[j];
if(cmp((p[j]-q)&(mx-q))==1)mx=p[j];
}
// q.print(),mn.print(),mx.print(),puts("");
L[i]=findlimit(Line(q,mn),1,side(q.x,q.y));
R[i]=findlimit(Line(q,mx),-1,side(q.x,q.y));
// printf("%d %d\n",L[i],R[i]);
}
ll res=0;
for(int i=0,j=1;i<N;){
if(L[i]<i)break;
while(j!=(R[i]+1)%N)modify(j,1),(++j)%=N;
res+=query(1,0,N-1,L[i],4*m-1);
// printf("%d\n",res);
modify(++i,-1);
}
return res;
}
}my;
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?