Luogu P3806 【模板】点分治
前言:
本文简述点分治。
约定:
本文除标程外,均只讨论一次询问。
用一般dfs解决这个问题:
我们可以先预处理出所有可能的距离,则可以\(O(1)\)查询。
可以对每个节点\(i\)维护一个\(fd\)数组,表示以\(i\)为根的子树中,以\(i\)为端点的链的长度有哪些值能取到,最终时间复杂度为\(O(n^2)\),由于该题时限很短,无法通过。
点分治:
发现若一般dfs遇到一颗深度为\(O(\log n)\)的树,可以不使用bitset,转而使用普通数组,这样可以精确控制转移,可以只转移实际存在的链长度。那么时间复杂度十分优秀\(O(n\log n)\)。
考虑能不能对普通的树进行转化,使得其变为深度为\(O(\log n)\)的树。
假设当前遍历到以\(root\)为根的子树,则可以将路径分为经过\(root\)和不经过\(root\),这是普通dfs的思想。
考虑处理完经过\(root\)的路径后,剩下的若干子树如何快速处理。
发现处理这些子树时,以哪个节点为根并不重要,所以可以直接以该子树的重心为根。
这样每次都选重心,则剩下的连通块大小会不断\(/2\),所以递归深度是\(O(\log n)\)的。
这样就达成了我们的目的——吗?
时间复杂度:
发现每次递归到一个节点,为了计算链长度,都需要重新遍历一遍整个子树,因为递归的时候不是向其儿子递归的。那么时间复杂度会有什么影响,考虑证明:
因为递归深度是\(O(\log n)\)的,而同一层递归到的子树一定是不交的,于是它们的大小之和是\(O(n)\)的,所以整体复杂度依旧为\(O(n\log n)\)。
标程:
#include<bits/stdc++.h>
using namespace std;
const int N = 1e4+5;
const int K = 1e7+5;
bool vis[N],fd[K],hs;
int siz[N],cq[N],cq2[N],cqtp2,cqtp,qtp,k,s;
int q[N][3],sn[3];
vector<pair<int,int> > edg[N];
void resiz(int now,int f){
siz[now] = 1;
for(auto& i : edg[now]){
if(i.first==f||vis[i.first]) continue;
resiz(i.first,now);
siz[now]+=siz[i.first];
}
}
int ask(int now,int f){
int ans = 0;
bool fg = true;
for(auto& i : edg[now]){
if(i.first==f||vis[i.first]) continue;
ans = max(ans,ask(i.first,now));
if(siz[i.first]>s/2) fg = false;
}
if(fg&&s-siz[now]<=s/2) return now;
return ans;
}
void sl(int now){
resiz(now,0);
s = siz[now];
now = ask(now,0);
cqtp2 = 0,fd[0] = true;
for(auto& i : edg[now]){
if(vis[i.first]) continue;
qtp = 0,cqtp = 0;
q[++qtp][0] = i.first;
q[qtp][1] = i.second;
q[qtp][2] = now;
while(qtp){
sn[0] = q[qtp][0];
sn[1] = q[qtp][1];
sn[2] = q[qtp--][2];
if(sn[1]>k) continue;
cq[++cqtp] = sn[1];
if(fd[k-sn[1]]){
hs = true;
for(;cqtp2;cqtp2--) fd[cq2[cqtp2]] = false;
return;
}
for(auto& j : edg[sn[0]]){
if(j.first==sn[2]||vis[j.first]) continue;
q[++qtp][0] = j.first;
q[qtp][1] = sn[1]+j.second;
q[qtp][2] = sn[0];
}
}
for(;cqtp;cqtp--){
fd[cq[cqtp]] = true;
cq2[++cqtp2] = cq[cqtp];
}
}
for(;cqtp2;cqtp2--) fd[cq2[cqtp2]] = false;
fd[0] = false;
vis[now] = true;
for(auto& i : edg[now]){
if(vis[i.first]) continue;
sl(i.first);
if(hs) return;
}
}
int main(){
cin.tie(nullptr)->sync_with_stdio(false);
int n,m;
cin>>n>>m;
for(int i=1,u,v,w;i<n;i++){
cin>>u>>v>>w;
edg[u].emplace_back(v,w);
edg[v].emplace_back(u,w);
}
while(m--){
hs = false;
cin>>k;
resiz(1,0);
s = siz[1];
for(int i=1;i<=n;i++) vis[i] = false;
sl(ask(1,0));
cout<<(hs?"AYE\n":"NAY\n");
}
return 0;
}

浙公网安备 33010602011771号