codeforces 331 D3.Escaping on Beaveractor - 线段树 - 基环树 - 倍增
2018-02-03 21:53
531 查看
传送门
题目大意:平面上有有些有向线段,平行于轴,当走到有向线段的时候自己的方向就要变成其方向,自己速度1。给定这些有向线段,多组数据,每组给出初始位置和初始方向和时间,问是否会走出边界,如果不,输出最后在哪里,否则输出离开边界时候的坐标。数据都是1e5,时间1e15。
题解:题目本身很简单,把所有东西离线下来,用线段树处理出从询问点或者某个有向线段的箭头处开始走会走到哪一个点方向发生转折,以及所用时间,并建图。如果走到边界,那么边界建出的点想自己连边。这样每个点出度=1,就是内向基环树森林,这样倍增dis[x][y]表示从x出发走2^y点点的距离,询问时候走到环上之后用时间对环长度取模,然后继续倍增即可。本身不是很难基本上几分钟之内就能想出来但是……从早上写到晚上写了一整天QwQ.
最难写的应该是预处理部分的,一开始写了一遍,觉得写的太丑,情况太多,而且写到后面发现还有很多需要维护的东西之前如果不这么写就很好求,但是因为之前写的不好,后面的东西要重新求一边,所以就删了重构了一遍,就好多了。这题要维护四个方向,我就真的写了四遍预处理,然后因为复制粘贴没改全以及打错变量名之类的问题挂了很久。
去翻了翻别人的代码,可以用一些奇怪的语法,或者通过交换x,y轴及方向做到较好的代码合并。基环树部分还比较好写,好像一遍就写过了,后面倍增部分要判一些东西,也还可以。
Notes,1.写维护东西比较繁杂的题一定要先确定总共维护什
4000
么东西,例如当前可以维护a和b,但是用a可以很快的知道b,例如,知道下标就很容易知道权值,但是知道权值反过来维护下标就不舒服。这样事先确定维护什么东西,在此基础上决定怎么实现,要比要什么就维护什么好得多,后者经常要重构,就很麻烦。
2.写之前一定要合并一些情况,否则讨论起来太麻烦,例如这个题里面点可以看作长度=0的有向线段,这样就可以把点和线段看成一种东西维护,以及把四个方向看成xy轴的颠倒和交换,就避免考虑什么到底是x1还是x2还是大于还是小于的问题,避免打错变量名或者其它细节之类的。
代码:
题目大意:平面上有有些有向线段,平行于轴,当走到有向线段的时候自己的方向就要变成其方向,自己速度1。给定这些有向线段,多组数据,每组给出初始位置和初始方向和时间,问是否会走出边界,如果不,输出最后在哪里,否则输出离开边界时候的坐标。数据都是1e5,时间1e15。
题解:题目本身很简单,把所有东西离线下来,用线段树处理出从询问点或者某个有向线段的箭头处开始走会走到哪一个点方向发生转折,以及所用时间,并建图。如果走到边界,那么边界建出的点想自己连边。这样每个点出度=1,就是内向基环树森林,这样倍增dis[x][y]表示从x出发走2^y点点的距离,询问时候走到环上之后用时间对环长度取模,然后继续倍增即可。本身不是很难基本上几分钟之内就能想出来但是……从早上写到晚上写了一整天QwQ.
最难写的应该是预处理部分的,一开始写了一遍,觉得写的太丑,情况太多,而且写到后面发现还有很多需要维护的东西之前如果不这么写就很好求,但是因为之前写的不好,后面的东西要重新求一边,所以就删了重构了一遍,就好多了。这题要维护四个方向,我就真的写了四遍预处理,然后因为复制粘贴没改全以及打错变量名之类的问题挂了很久。
去翻了翻别人的代码,可以用一些奇怪的语法,或者通过交换x,y轴及方向做到较好的代码合并。基环树部分还比较好写,好像一遍就写过了,后面倍增部分要判一些东西,也还可以。
Notes,1.写维护东西比较繁杂的题一定要先确定总共维护什
4000
么东西,例如当前可以维护a和b,但是用a可以很快的知道b,例如,知道下标就很容易知道权值,但是知道权值反过来维护下标就不舒服。这样事先确定维护什么东西,在此基础上决定怎么实现,要比要什么就维护什么好得多,后者经常要重构,就很麻烦。
2.写之前一定要合并一些情况,否则讨论起来太麻烦,例如这个题里面点可以看作长度=0的有向线段,这样就可以把点和线段看成一种东西维护,以及把四个方向看成xy轴的颠倒和交换,就避免考虑什么到底是x1还是x2还是大于还是小于的问题,避免打错变量名或者其它细节之类的。
代码:
//http://codeforces.com/contest/331/problem/D3 #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<vector> #include<stack> #define R 0 #define D 1 #define L 2 #define U 3 #define lint long long #define N 400010 #define M N<<1 #define LOG 24 #define debug(x) cerr<<#x<<"="<<x #define sp <<" " #define ln <<endl using namespace std; struct point{ int x1,x2,y1,y2,kind,id,dir; int mxx,mnx,mxy,mny; inline int get_dir() { if(x1^x2) dir=(x1<x2?0:2); else dir=(y1<y2?3:1); return 0; } inline int init() { return mxx=max(x1,x2),mnx=min(x1,x2),mxy=max(y1,y2),mny=min(y1,y2); } void show() { debug(kind)sp,debug(x1)sp,debug(y1)sp,debug(x2)sp,debug(y2)sp,debug(dir)sp,debug(id)ln; } }a ; inline int get_dir(int x1,int y1,int x2,int y2) { if(x1^x2) return x1<x2?0:2; else return y1<y2?3:1; } inline bool xcmp1(const point &p1,const point &p2) { if(p1.mnx^p2.mnx) return p1.mnx<p2.mnx; else return p1.kind<p2.kind; } inline bool xcmp2(const point &p1,const point &p2) { if(p1.mxx^p2.mxx) return p1.mxx>p2.mxx; else return p1.kind<p2.kind; } inline bool ycmp1(const point &p1,const point &p2) { if(p1.mxy^p2.mxy) return p1.mxy>p2.mxy; else return p1.kind<p2.kind; } inline bool ycmp2(const point &p1,const point &p2) { if(p1.mny^p2.mny) return p1.mny<p2.mny; else return p1.kind<p2.kind; } inline int gabs(int x) { return x<0?-x:x; } int dx[4]={1,0,-1,0},dy[4]={0,-1,0,1}; int to ,state ,up [LOG],val ; bool on_cir ;lint dis [LOG]; int X ,Y ;lint qt ,cl ,ansx ,ansy ; struct edges{ int to,pre,wgt; }e[M];int h ,etop; inline int add_edge(int u,int v,int w) { e[++etop].to=v,e[etop].pre=h[u]; return e[etop].wgt=w,h[u]=etop; } struct segment{ int l,r,v;bool pt; segment *ch[2]; }*rt; int build(segment* &rt,int l,int r) { rt=new segment;rt->l=l,rt->r=r;int mid=(l+r)>>1; rt->pt=true,rt->v=0;if(l==r) return rt->v=0; build(rt->ch[0],l,mid),build(rt->ch[1],mid+1,r); return 0; } inline int push_down(segment* &rt) { return rt->ch[0]->v=rt->ch[1]->v=rt->v, rt->ch[0]->pt=rt->ch[1]->pt=true,rt->pt=false; } int update(segment* &rt,int s,int t,int v) { int l=rt->l,r=rt->r,mid=(l+r)>>1; if(s<=l&&r<=t) return rt->v=v,rt->pt=true; if(rt->pt) push_down(rt); if(s<=mid) update(rt->ch[0],s,t,v); if(mid<t) update(rt->ch[1],s,t,v); return 0; } int query(segment* &rt,int p) { int l=rt->l,r=rt->r,mid=(l+r)>>1; if(l==r) return rt->v; if(rt->pt) push_down(rt); if(p<=mid) return query(rt->ch[0],p); else return query(rt->ch[1],p); } int get_tree(int x,int f) { if(!on_cir[x]) for(int i=1;i<LOG;i++) up[x][i]=up[up[x][i-1]][i-1], dis[x][i]=dis[x][i-1]+dis[up[x][i-1]][i-1]; for(int i=h[x],y;i;i=e[i].pre) if((y=e[i].to)^f) up[y][0]=x,dis[y][0]=e[i].wgt,get_tree(y,x); return 0; } vector<int> vc;bool vis ;stack<int> stc; int get_val(int x) { vc.clear(),vc.push_back(0);lint ccl=0; while(!vis[x]) vis[x]=true,ccl+=val[x],vc.push_back(x=to[x]); for(int i=1;i<(int)vc.size();i++) up[vc[i]][0]=to[vc[i]],dis[vc[i]][0]=val[vc[i]],cl[vc[i]]=ccl; for(int j=1;j<LOG;j++) for(int i=1;i<(int)vc.size();i++) up[vc[i]][j]=up[up[vc[i]][j-1]][j-1], dis[vc[i]][j]=dis[vc[i]][j-1]+dis[up[vc[i]][j-1]][j-1]; for(int i=1;i<(int)vc.size();i++) get_tree(vc[i],to[vc[i]]); return 0; } int main() { freopen("331D.in","r",stdin); int m,n;scanf("%d%d",&m,&n); build(rt,1,n+1); for(int i=1;i<=m;i++) { scanf("%d%d%d%d",&a[i].x1,&a[i].y1,&a[i].x2,&a[i].y2); a[i].id=i,a[i].get_dir(),a[i].kind=0; // debug(i)sp,a[i].show(); } int q,pc;scanf("%d",&q),pc=m+q; for(int i=1;i<=q;i++) { char ch;scanf("%d%d %c%lld",&a[i+m].x1,&a[i+m].y1,&ch,&qt[i]); a[i+m].id=i+m,a[i+m].kind=1;a[i+m].x2=a[i+m].x1,a[i+m].y2=a[i+m].y1; if(ch=='R') a[i+m].dir=0;if(ch=='D') a[i+m].dir=1; if(ch=='L') a[i+m].dir=2;if(ch=='U') a[i+m].dir=3; // debug(i+m)sp,a[i+m].show(); } for(int i=1;i<=m+q;i++) a[i].init(); #define add_edge(u,v,c) to[u]=v,val[u]=c sort(a+1,a+m+q+1,xcmp1),update(rt,1,n+1,0); for(int i=1;i<=m+q;i++) { if(!a[i].kind) { if(a[i].dir==U) update(rt,a[i].y1+1,a[i].y2+1,i); else if(a[i].dir==D) update(rt,a[i].y2+1,a[i].y1+1,i); else if(a[i].dir==R) update(rt,a[i].y1+1,a[i].y2+1,i); } if(a[i].dir==L) { int t=query(rt,a[i].y1+1); pc++,a[pc].id=pc,a[pc].y1=a[i].y1; if(t) { if(a[t].dir!=R) add_edge(pc,a[t].id,gabs(a[i].y2-a[t].y2)),a[pc].x1=a[t].x1; else add_edge(pc,a[t].id,max(0,a[t].x2-a[i].x2)),a[pc].x1=min(a[t].x2,a[i].x2); add_edge(a[i].id,pc,max(0,a[i].x2-a[t].x2)); } else add_edge(pc,pc,1),add_edge(a[i].id,pc,a[i].x2),a[pc].x1=0; } } sort(a+1,a+m+q+1,xcmp2),update(rt,1,n+1,0); for(int i=1;i<=m+q;i++) { if(!a[i].kind) { if(a[i].dir==U) update(rt,a[i].y1+1,a[i].y2+1,i); else if(a[i].dir==D) update(rt,a[i].y2+1,a[i].y1+1,i); else if(a[i].dir==L) update(rt,a[i].y1+1,a[i].y2+1,i); } if(a[i].dir==R) { int t=query(rt,a[i].y1+1); pc++,a[pc].id=pc,a[pc].y1=a[i].y1; if(t) { if(a[t].dir!=L) add_edge(pc,a[t].id,gabs(a[i].y2-a[t].y2)),a[pc].x1=a[t].x1; else add_edge(pc,a[t].id,max(0,a[i].x2-a[t].x2)),a[pc].x1=max(a[t].x2,a[i].x2); add_edge(a[i].id,pc,max(0,a[t].x2-a[i].x2)); } else add_edge(pc,pc,1),add_edge(a[i].id,pc,n-a[i].x2),a[pc].x1=n; } } sort(a+1,a+m+q+1,ycmp1),update(rt,1,n+1,0); for(int i=1;i<=m+q;i++) { if(!a[i].kind) { if(a[i].dir==L) update(rt,a[i].x2+1,a[i].x1+1,i); else if(a[i].dir==R) update(rt,a[i].x1+1,a[i].x2+1,i); else if(a[i].dir==D) update(rt,a[i].x1+1,a[i].x2+1,i); } if(a[i].dir==U) { int t=query(rt,a[i].x1+1); pc++,a[pc].id=pc,a[pc].x1=a[i].x1; if(t) { if(a[t].dir!=D) add_edge(pc,a[t].id,gabs(a[i].x2-a[t].x2)),a[pc].y1=a[t].y1; else add_edge(pc,a[t].id,max(0,a[i].y2-a[t].y2)),a[pc].y1=max(a[t].y2,a[i].y2); add_edge(a[i].id,pc,max(0,a[t].y2-a[i].y2)); } else add_edge(pc,pc,1),add_edge(a[i].id,pc,n-a[i].y2),a[pc].y1=n; } } sort(a+1,a+m+q+1,ycmp2),update(rt,1,n+1,0); for(int i=1;i<=m+q;i++) { if(!a[i].kind) { if(a[i].dir==L) update(rt,a[i].x2+1,a[i].x1+1,i); else if(a[i].dir==R) update(rt,a[i].x1+1,a[i].x2+1,i); else if(a[i].dir==U) update(rt,a[i].x1+1,a[i].x2+1,i); } if(a[i].dir==D) { int t=query(rt,a[i].x1+1); pc++,a[pc].id=pc,a[pc].x1=a[i].x1; if(t) { if(a[t].dir!=U) add_edge(pc,a[t].id,gabs(a[i].x2-a[t].x2)),a[pc].y1=a[t].y1; else add_edge(pc,a[t].id,max(0,a[t].y2-a[i].y2)),a[pc].y1=min(a[t].y2,a[i].y2); add_edge(a[i].id,pc,max(0,a[i].y2-a[t].y2)); } else add_edge(pc,pc,1),add_edge(a[i].id,pc,a[i].y2),a[pc].y1=0; } } for(int i=m+q+1;i<=pc;i++) a[i].x2=a[i].x1,a[i].y2=a[i].y1,a[i].init(); #undef add_edge // cerr ln; // for(int i=1;i<=pc;i++) debug(i)sp,debug(to[i])sp,debug(val[i])ln; // cerr ln; for(int i=1,x,f,t;i<=pc;i++) if(state[i]!=2) { stc.push(x=i),state[x]=1,f=true,t=0; while(state[to[x]]!=2) if(!state[to[x]]) stc.push(x=to[x]),state[x]=1; else on_cir[to[x]]=true,t=to[x],state[to[x]]=2; while(!stc.empty()) on_cir[stc.top()]=(f&&t),f&=((t==stc.top())^1), state[stc.top()]=2,stc.pop(); } for(int i=1;i<=pc;i++) if(on_cir[i]) add_edge(i,to[i],val[i]); else add_edge(to[i],i,val[i]); for(int i=1;i<=pc;i++) if(on_cir[i]&&!vis[i]) get_val(i); for(int i=1;i<=pc;i++) X[a[i].id]=a[i].x2,Y[a[i].id]=a[i].y2; // for(int i=1;i<=pc;i++) // if(on_cir[i]) cerr<<i<<" is on circle.\n";cerr ln; // for(int i=1;i<=pc;i++) // debug(i)sp,debug(up[i][0])sp,debug(up[i][1])sp,debug(up[i][2])sp,debug(up[i][3])ln, // debug(i)sp,debug(dis[i][0])sp,debug(dis[i][1])sp,debug(dis[i][2])sp,debug(dis[i][3])ln;cerr ln; for(int i=1;i<=pc;i++) if(a[i].kind) { int k=a[i].id,c=k-m;lint t=qt[c];//debug(c)sp,debug(k)sp,debug(t)ln; for(int j=LOG-1;j>=0;j--) if(!on_cir[up[k][j]]&&t>=dis[k][j]) t-=dis[k][j],k=up[k][j]; // debug(k)sp,debug(t)ln; if(t>=val[k]) t-=val[k],k=to[k]; if(on_cir[k]) t%=cl[k]; for(int j=LOG-1;j>=0;j--) if(t>=dis[k][j]) t-=dis[k][j],k=up[k][j]; // debug(k)sp,debug(t)sp,debug(X[k])sp,debug(Y[k])ln; int d=get_dir(X[k],Y[k],X[to[k]],Y[to[k]]); // debug(d)sp,debug(dx[d])sp,debug(dy[d])ln;cerr ln; ansx[c]=X[k]+dx[d]*t,ansy[c]=Y[k]+dy[d]*t; } for(int i=1;i<=q;i++) printf("%lld %lld\n",ansx[i],ansy[i]); return 0; }
相关文章推荐
- Codeforces 622C Not Equal on a Segment 【线段树 Or DP】
- 2588: Spoj 10628. Count on a tree[可持久化线段树+倍增lca]
- Codeforces 622C Not Equal on a Segment 【线段树 Or DP】
- Codeforces-242E:XOR on Segment(20个线段树)
- Codeforces Round #424 (Div. 2, rated, based on VK Cup Finals) Problem E (Codeforces 831E) - 线段树 - 树状数组
- CodeForces 242E - XOR on Segment 二维线段树?
- CodeForces 242E - XOR on Segment 二维线段树?
- CodeForces 276E - Little Girl and Problem on Trees 区间更新..N+1个线段树
- Codeforces 242E- XOR on Segment(线段树)
- Codeforces 622C Not Equal on a Segment 【线段树 or dp】
- codeforces 46D 线段树 区间合并
- Codeforces刷题之路——266A Stones on the Table
- 【Codeforces】Codeforces Round #299 (Div. 1) E. Tavas on the Path 【树链剖分+区间合并】
- CodeForces 19D Points(离散化+线段树+单点更新)
- codeforces 675D D. Tree Construction(线段树+BTS)
- 【CodeForces】622C - Not Equal on a Segment
- Codeforces 435 A Queue on Bus Stop
- 【Codeforces811E】Vladik and Entertaining Flags [线段树][并查集]
- hdoj 4288 && Codeforces 85D Coder 【线段树】
- Codeforces 622C Not Equal on a Segment【思维预处理+二分】