生活随笔
收集整理的這篇文章主要介紹了
NOIP2016洛谷P1600:天天爱跑步
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
文章目錄
- 解析
- sol1:樹剖+map
- sol2:樹剖+離線
- sol3:dfs維護(hù)樹狀數(shù)組+差分
解析
個人認(rèn)為本題比同年的逛公園可做許多
本題的一個關(guān)鍵是:把慢跑者(u,v)(u,v)(u,v)轉(zhuǎn)化為上升路徑上滿足depx+tx=depudep_x+t_x=dep_udepx?+tx?=depu?的結(jié)點和下降路徑上滿足?dep+x+tx=depu?2?deplca-dep+x+t_x=dep_u-2*dep_{lca}?dep+x+tx?=depu??2?deplca?的結(jié)點x的答案均加一
這個感覺不是很難想,由于每秒跑一步的特性,很容易想到這個和深度的聯(lián)系
然后就是怎么維護(hù)上面那個玩意了
sol1:樹剖+map
時間復(fù)雜度:O(nlogn^3)
得分:95pts
這是我一開始想到的解法
第一交95pts也可以接受了吧
極其好寫
就是對線段樹每個結(jié)點開個map,做一個標(biāo)記永久化,然后詢問的時候沿途把標(biāo)記撿起來就行了
修改過程中只會在最終打標(biāo)記處改變map
一開始我覺得這個改變次數(shù)是O(1)的,但是這個是**假的!!**在最差情況下會退化成Ologn個(比如修改[1,n-1]的區(qū)間時)
這樣復(fù)雜度就升到了nlogn^3,無法通過了
T掉3e5的數(shù)據(jù)也是合情合理
由于樹剖自帶的小常數(shù)+氧氣加持+上面那個第三個log完全跑不滿(現(xiàn)在終于可以默認(rèn)有O2了!),得到95分也算合理
(然而關(guān)掉氧氣由于垃圾的map常數(shù)就只有25pts)
sol2:樹剖+離線
時間復(fù)雜度:nlogn^2
得分:100pts
稍微思考一下就可以想到真的做法
注意到所有的操作和詢問都是針對一個特定的值,把他們離線下來從大到小處理即可
詢問的時候用到一個先減后加從而求出變化量
這個就跑的飛快了
也不再耗氧
### 代碼
#include<bits/stdc++.h>
using namespace std
;
#define ll long long
#define il inline
#define debug(a,b) fprintf(stderr,a,b)
const int N
=3e5+100;
const double eps
=1e-9;
inline ll
read() {ll x
=0,f
=1;char c
=getchar();while(!isdigit(c
)) {if(c
=='-') f
=-1;c
=getchar();}while(isdigit(c
)) {x
=(x
<<1)+(x
<<3)+c
-'0';c
=getchar();}return x
*f
;
}int n
,m
;
struct node {int to
,nxt
;
} p
[N
<<1];
int fi
[N
],cnt
;
inline void addline(int x
,int y
) {p
[++cnt
]=(node
) {y
,fi
[x
]};fi
[x
]=cnt
;return;
}
int fa
[N
],siz
[N
],dep
[N
],hson
[N
],top
[N
],dfn
[N
],pos
[N
],tim
;
void dfs1(int x
,int f
) {fa
[x
]=f
;dep
[x
]=dep
[f
]+1;siz
[x
]=1;for(int i
=fi
[x
]; ~i
; i
=p
[i
].nxt
) {int to
=p
[i
].to
;if(to
==f
) continue;dfs1(to
,x
);siz
[x
]+=siz
[to
];if(siz
[to
]>siz
[hson
[x
]]) hson
[x
]=to
;}return;
}
void dfs2(int x
,int tp
) {top
[x
]=tp
;dfn
[++tim
]=x
;pos
[x
]=tim
;if(hson
[x
]) dfs2(hson
[x
],tp
);for(int i
=fi
[x
]; ~i
; i
=p
[i
].nxt
) {int to
=p
[i
].to
;if(to
==hson
[x
]||to
==fa
[x
]) continue;dfs2(to
,to
);}return;
}
inline int Lca(int x
,int y
){while(top
[x
]!=top
[y
]){if(dep
[top
[x
]]<dep
[top
[y
]])swap(x
,y
);x
=fa
[top
[x
]];} if(dep
[x
]<dep
[y
]) swap(x
,y
);return y
;
}#define mid ((l+r)>>1)
#define ls (k<<1)
#define rs (k<<1|1)int ans
[N
];struct tree{int val
[N
<<2];int ask(int k
,int l
,int r
,int x
){int res
=val
[k
];if(l
==r
) return res
;if(x
<=mid
) return ask(ls
,l
,mid
,x
)+res
;else return ask(rs
,mid
+1,r
,x
)+res
;}void change(int k
,int l
,int r
,int x
,int y
){if(x
>y
) return;if(x
<=l
&&r
<=y
){val
[k
]++;return;}if(x
<=mid
) change(ls
,l
,mid
,x
,y
);if(y
>mid
) change(rs
,mid
+1,r
,x
,y
);return;}inline void Add(int x
,int anc
,int flag
){while(top
[x
]!=top
[anc
]){change(1,1,n
,pos
[top
[x
]],pos
[x
]);x
=fa
[top
[x
]];}change(1,1,n
,pos
[anc
]+flag
,pos
[x
]);return;}
}t
[2];int tt
[N
];int tot1
,tot2
;
struct ope{int x
,anc
,val
,op
;bool operator < (const ope u
)const{return val
<u
.val
;}
}o
[N
<<1];
struct query{int x
,val
,op
;bool operator < (const query u
)const{return val
<u
.val
;}
}q
[N
<<1];
int main() {
#ifndef ONLINE_JUDGE
#endifmemset(fi
,-1,sizeof(fi
));cnt
=-1;n
=read();m
=read();for(int i
=1; i
<n
; i
++) {int x
=read(),y
=read();addline(x
,y
);addline(y
,x
);}dfs1(1,0);dfs2(1,1);for(int i
=1;i
<=n
;i
++){tt
[i
]=read();q
[++tot1
]=(query
){i
,tt
[i
]+dep
[i
],0};q
[++tot1
]=(query
){i
,tt
[i
]-dep
[i
],1};}for(int i
=1;i
<=m
;i
++){int x
=read(),y
=read();int lca
=Lca(x
,y
);o
[++tot2
]=(ope
){x
,lca
,dep
[x
],0};o
[++tot2
]=(ope
){y
,lca
,dep
[x
]-2*dep
[lca
],1};}sort(q
+1,q
+1+tot1
);sort(o
+1,o
+1+tot2
);int pl1
=1,pl2
=1;for(int tim
=-2*n
;tim
<=2*n
;tim
++){for(int i
=pl1
;i
<=tot1
&&q
[i
].val
==tim
;i
++){int now
=q
[i
].x
;ans
[now
]-=t
[q
[i
].op
].ask(1,1,n
,pos
[now
]);}while(pl2
<=tot2
&&o
[pl2
].val
==tim
){t
[o
[pl2
].op
].Add(o
[pl2
].x
,o
[pl2
].anc
,o
[pl2
].op
);++pl2
;}while(pl1
<=tot1
&&q
[pl1
].val
==tim
){int now
=q
[pl1
].x
;ans
[now
]+=t
[q
[pl1
].op
].ask(1,1,n
,pos
[now
]);++pl1
;}}for(int i
=1;i
<=n
;i
++){printf("%d ",ans
[i
]);}return 0;
}
sol3:dfs維護(hù)樹狀數(shù)組+差分
時間復(fù)雜度:nlogn
得分:100pts
寫完看的題解的思路
這個東西是真的好強(qiáng)大
有點四兩撥千斤的感覺
以后可以多往這方面想一想
就是把我上面維護(hù)的東西離線到各個結(jié)點上
維護(hù)樹狀數(shù)組并利用前后差值求出答案
(應(yīng)該)跑的飛快
說是應(yīng)該是因為我并沒有再寫一遍
總結(jié)
以上是生活随笔為你收集整理的NOIP2016洛谷P1600:天天爱跑步的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。