点分治 学习笔记
点分治是树上暴力的优化,可以让 \(O(n^2)\) (枚举树上任意两点)的时间复杂度降为 \(O(n \log{n})\)。
简单证明一下时间复杂度:
每次都取树的重心进行递归,则每次递归子树大小减半,递归至多 \(\log{n}\) 层。每一层有 \(n\) 个点,故时间复杂度 \(O(n \log{n})\)。
例题:P3806 【模板】点分治 1
朴素的想法是:枚举树上任意两点,用倍增在求 lca 的同时求出两点间路径长度。时间复杂度 \(O(n^2 \log{n})\)。
考虑点分治优化暴力。
(咕)
#include<bits/stdc++.h>
// #define int long long
using namespace std;
const int Size=(1<<20)+1;
char buf[Size],*p1=buf,*p2=buf;
char buffer[Size];
int op1=-1;
const int op2=Size-1;
#define getchar() \
(tt == ss && (tt=(ss=In)+fread(In, 1, 1 << 20, stdin), ss == tt) \
? EOF \
: *ss++)
char In[1<<20],*ss=In,*tt=In;
inline int read()
{
int x=0,c=getchar(),f=0;
for(;c>'9'||c<'0';f=c=='-',c=getchar());
for(;c>='0'&&c<='9';c=getchar())
x=(x<<1)+(x<<3)+(c^48);
return f?-x:x;
}
inline void write(int x)
{
if(x<0) x=-x,putchar('-');
if(x>9) write(x/10);
putchar(x%10+'0');
}
int n,m;
vector<int> E[10005],V[10005];
bool vis[10005];
int qu[104];
const int MAXN=1e7;
//
//void add(int p,int k)
//{
// for(int i=p;i<=MAXN;i+=lowbit(i)) t[i]+=k;
//}
//
//int query1(int p)
//{
// int ans=0;
// for(int i=p;i>0;i-=lowbit(i)) ans+=t[i];
// return ans;
//}
//
//int query(int l,int r)
//{
// return query1(r)-query1(l-1);
//}
void addddd(int u,int v,int w) { E[u].push_back(v); V[u].push_back(w); }
int siz[10005];
bool can[10005];
// int O;
void dfs1(int p,int fa)
{
// O++;
siz[p]=1;
for(int i=0;i<E[p].size();i++)
{
int to=E[p][i];
if(to==fa||vis[to]) continue;
dfs1(to,p);
siz[p]+=siz[to];
}
}
//abs(maxn_siz-min_siz) 's minnum
//(abs,p)
inline pair<int,int> minn(pair<int,int> x,pair<int,int> y)
{
if(x.first<y.first) return x;
else return y;
}
inline pair<int,int> dfs2(int p,int fa,const int maxn_siz)
{
// int nw=n+1,x=p,up=maxn_siz-siz[p],down=0;
// O++;
pair<int,int> ans1=make_pair(MAXN,0);
int maxn=0;
for(int i=0;i<E[p].size();i++)
{
int to=E[p][i];
if(to==fa||vis[to]) continue;
ans1=minn(ans1,dfs2(to,p,maxn_siz));
maxn=max(maxn,siz[to]);
// up-=siz[to];
// down+=siz[to];
}
// if((abs(maxn_siz-siz[p]-siz[p]))<100000)cout<<"p="<<p<<" abs="<<(abs(maxn_siz-siz[p]-siz[p]))<<"\n";
return minn(ans1,make_pair(max(maxn,maxn_siz-siz[p]),p));
}
bool f[MAXN+10];
vector<int> v,v2;
void dfs3(int p,int fa,int dis)
{
// O++;
if(dis>MAXN) return;
v.push_back(dis);
v2.push_back(dis);
// f[dis]=1;
for(int i=0;i<E[p].size();i++)
{
int to=E[p][i];
int w=V[p][i];
if(to==fa||vis[to]) continue;
// v.push_back()
dfs3(to,p,dis+w);
}
}
void solve(int root)
{
// O++;
vis[root]=1;
siz[root]=0;
// cout<<root<<"\n";
for(int i=0;i<E[root].size();i++)
{
int to=E[root][i];
if(vis[to]) continue;
dfs1(to,root);
int to_root=dfs2(to,root,siz[to]).second;
// cout<<to_root<<"\n";
if(!(to_root<1||to_root>n))
{
solve(to_root);
}
}
for(int i=0;i<v2.size();i++) f[v2[i]]=0;
v2.clear();
for(int i=0;i<E[root].size();i++)
{
int to=E[root][i];
int w=V[root][i];
// cout<<w<<"\n";
if(vis[to]) continue;
v.clear();
dfs3(to,root,w);
for(int k=1;k<=m;k++)
{
if(can[k]) continue;
for(int j=0;j<v.size();j++) if((qu[k]<=MAXN&&qu[k]-v[j]>=0&&f[qu[k]-v[j]])||v[j]==qu[k]) can[k]=1;
}
for(int j=0;j<v.size();j++) f[v[j]]=1;
}
vis[root]=0;
// return f[k];
}
signed main()
{
// freopen("P3806_8.in","r",stdin);
// freopen("a.out","w",stdout);
n=read();
m=read();
// k=read();
for(int i=1;i<n;i++)
{
int u=read(),v=read(),w=read();
addddd(u,v,w);
addddd(v,u,w);
}
dfs1(1,0);
int root=dfs2(1,0,n).second;
// cout<<root<<"\n";
for(int i=1;i<=m;i++)
{
qu[i]=read();
}
solve(root);
for(int i=1;i<=m;i++)
{
if(qu[i]<=10000000&&can[i]) cout<<"AYE\n";
else cout<<"NAY\n";
}
// cout<<O<<"\n";
//mt19937_64 myrand(time(0));
return 0;
}
以下是博客签名,正文无关
本文来自博客园,作者:Wy_x,转载请在文首注明原文链接:https://www.cnblogs.com/Wy-x/p/18970507
版权声明:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议(CC-BY-NC-SA 4.0 协议)进行许可。

浙公网安备 33010602011771号