codeforces 331 D3.Escaping on Beaveractor
傳送門
題目大意:平面上有有些有向線段,平行於軸,當走到有向線段的時候自己的方向就要變成其方向,自己速度1。給定這些有向線段,多組資料,每組給出初始位置和初始方向和時間,問是否會走出邊界,如果不,輸出最後在哪裡,否則輸出離開邊界時候的座標。資料都是1e5,時間1e15。
題解:題目本身很簡單,把所有東西離線下來,用線段樹處理出從詢問點或者某個有向線段的箭頭處開始走會走到哪一個點方向發生轉折,以及所用時間,並建圖。如果走到邊界,那麼邊界建出的點想自己連邊。這樣每個點出度=1,就是內向基環樹森林,這樣倍增dis[x][y]表示從x出發走2^y點點的距離,詢問時候走到環上之後用時間對環長度取模,然後繼續倍增即可。本身不是很難基本上幾分鐘之內就能想出來但是……從早上寫到晚上寫了一整天QwQ.
最難寫的應該是預處理部分的,一開始寫了一遍,覺得寫的太醜,情況太多,而且寫到後面發現還有很多需要維護的東西之前如果不這麼寫就很好求,但是因為之前寫的不好,後面的東西要重新求一邊,所以就刪了重構了一遍,就好多了。這題要維護四個方向,我就真的寫了四遍預處理,然後因為複製貼上沒改全以及打錯變數名之類的問題掛了很久。
去翻了翻別人的程式碼,可以用一些奇怪的語法,或者通過交換x,y軸及方向做到較好的程式碼合併。基環樹部分還比較好寫,好像一遍就寫過了,後面倍增部分要判一些東西,也還可以。
Notes,1.寫維護東西比較繁雜的題一定要先確定總共維護什麼東西,例如當前可以維護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[N];
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[N],state[N],up[N][LOG],val[N];
bool on_cir[N];lint dis[N][LOG];
int X[N],Y[N];lint qt[N],cl[N],ansx[N],ansy[N];
struct edges{
int to,pre,wgt;
}e[M];int h[N],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[N];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;
}