您的位置:首页 > 其它

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还是大于还是小于的问题,避免打错变量名或者其它细节之类的。

代码:

//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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: