對最小包圓算法還不了解的可以先做這題。
因為他有保證詢問的區間總和不超過10^6,所以只要期望線性的作法就行了。
我們剩下的任務就是好好維護原序列。
其實除掉最小包圓之後留下來的問題就很單純了:維護兩顆可分裂合併Treap(or Splay),該做什麼操作就好好做那個操作就可以了。
細節上要注意reverse的tag傳遞要想清楚,不要寫錯。
還有一個神奇的地方是,code中用到的random_shuffle是用來防止特殊測資讓最小包圓算法失效的動作。
我原本只用了1次random_shuffle結果怎麼樣都過不了第5個testcase
後來我突發奇想再多用了一次,竟然又多錯了一筆!?
我就想:那就再多用一次好了,了不起再多錯一筆。
然後就AC了。幾十億人都驚呆了。
#define LL long long #define DB double #include<ctime> #include<algorithm> #include<cstdio> #include<vector> #include<cassert> using namespace std; unsigned ran() { static unsigned x=20150307; return x=x*0xdefaced+1; } struct Node { Node *lc,*rc; LL rev,val,pri,size; void push() { if(!rev) return; if(lc) lc->rev^=1; if(rc) rc->rev^=1; swap(lc,rc); rev=0; } void pull() {size=(lc?lc->size:0)+(rc?rc->size:0)+1;} Node() {} Node(LL x) {size=1;rev=0;pri=ran();val=x;lc=rc=NULL;} }*root[2]; Node* merge(Node* a,Node* b) { if(!a || !b) return a?a:b; else if(a->pri > b->pri) { a->push(); a->rc=merge(a->rc,b); a->pull(); return a; } else { b->push(); b->lc=merge(a,b->lc); b->pull(); return b; } } void split(Node* t,LL k,Node* &a,Node* &b) { if(!t) {a=b=NULL;return;} t->push(); if(((t->lc?t->lc->size:0)+1)<=k) { a=t; split(t->rc,k-(t->lc?t->lc->size:0)-1,a->rc,b); a->pull(); } else { b=t; split(t->lc,k,a,b->lc); b->pull(); } } void dfs(Node* now,vector<DB>& vec) { if(!now) return; now->push(); dfs(now->lc,vec); vec.push_back(now->val); dfs(now->rc,vec); now->pull(); } struct Point { DB x,y; Point() {} Point(DB _x,DB _y):x(_x),y(_y) {} }; typedef Point Vector; Vector operator + (const Vector& A,const Vector& B) {return Vector(A.x+B.x,A.y+B.y);} Vector operator * (const Vector& A,const DB& t) {return Vector(A.x*t,A.y*t);} Vector operator - (const Vector& A,const Vector& B) {return Vector(A.x-B.x,A.y-B.y);} DB dis(const Point& A,const Point& B) {return sqrt((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y));} DB Cross(const Vector& A,const Vector& B) {return A.x*B.y-B.x*A.y;} Point LineIntersec(Point& P,Vector& v,Point& Q,Vector& w) { Vector u=P-Q; DB t=Cross(w,u)/Cross(v,w); return P+v*t; } Point get_center(const Point& A,const Point& B,const Point& C) { Point P,v,Q,w; P=Point((A.x+B.x)*0.5,(A.y+B.y)*0.5); v=Vector(-(B.y-A.y),B.x-A.x); Q=Point((A.x+C.x)*0.5,(A.y+C.y)*0.5); w=Vector(-(C.y-A.y),C.x-A.x); return LineIntersec(P,v,Q,w); } vector<DB> vec; DB get_radius(Node* Tx,Node* Ty) { vector<Point> point; vec.clear(); dfs(Tx,vec); point.resize(vec.size()); for(LL i=0;i<point.size();i++) point[i].x=vec[i]; vec.clear(); dfs(Ty,vec); assert(vec.size()==point.size()); for(LL i=0;i<point.size();i++) point[i].y=vec[i]; random_shuffle(point.begin(),point.end()); random_shuffle(point.begin(),point.end()); random_shuffle(point.begin(),point.end()); Point center=Point(point[0].x,point[0].y); DB radius=0; LL n=point.size(); for(LL i=1;i<n;i++) { if(dis(point[i],center) < radius) continue; center=point[i]; for(LL j=0;j<i;j++) { if(dis(point[j],center) < radius) continue; center.x= (point[i].x+point[j].x)*0.5; center.y= (point[i].y+point[j].y)*0.5; radius= dis(point[j],center); for(LL k=0;k<j;k++) { if(dis(point[k],center) < radius) continue; center= get_center(point[i],point[j],point[k]); radius= dis(point[k],center); } } } return radius; } Node *t[6]; int main() { srand(time(NULL)); LL N,M; scanf("%lld%lld",&N,&M); for(LL i=0,x;i<N;i++) {scanf("%lld",&x);root[0]=merge(root[0],new Node(x));} for(LL i=0,x;i<N;i++) {scanf("%lld",&x);root[1]=merge(root[1],new Node(x));} for(LL i=0,type,id,L[2],R[2];i<M;i++) { scanf("%lld",&type); if(type==1) { scanf("%lld%lld%lld",&id,L,R); split(root[id],L[0]-1,t[0],t[1]); split(t[1],R[0]-L[0]+1,t[1],t[2]); t[1]->rev^=1; root[id]=merge(t[0],merge(t[1],t[2])); } else if(type==2) { scanf("%lld%lld%lld%lld%lld",&id,L,R,L+1,R+1); split(root[id],L[0]-1,t[0],t[1]); split(t[1],R[0]-L[0]+1,t[1],t[2]); split(t[2],L[1]-R[0]-1,t[2],t[3]); split(t[3],R[1]-L[1]+1,t[3],t[4]); root[id]=merge(t[0],merge(t[3],merge(t[2],merge(t[1],t[4])))); } else if(type==3) { scanf("%lld%lld",L,R); split(root[0],L[0]-1,t[0],t[1]); split(t[1],R[0]-L[0]+1,t[1],t[2]); split(root[1],L[0]-1,t[3],t[4]); split(t[4],R[0]-L[0]+1,t[4],t[5]); root[0]=merge(t[0],merge(t[4],t[2])); root[1]=merge(t[3],merge(t[1],t[5])); } else { scanf("%lld%lld",L,R); split(root[0],L[0]-1,t[0],t[1]); split(t[1],R[0]-L[0]+1,t[1],t[2]); split(root[1],L[0]-1,t[3],t[4]); split(t[4],R[0]-L[0]+1,t[4],t[5]); printf("%.2f\n",get_radius(t[1],t[4])); root[0]=merge(t[0],merge(t[1],t[2])); root[1]=merge(t[3],merge(t[4],t[5])); } } }
沒有留言:
張貼留言