点分治
心情不好所以没改题,滚回去打点分治了
说下点分治的思路,首先要求找到树的重心,然后根据树的重心作为根,把树翻过来.
接着再在其子树中各个重复该过程,然后就能保证深度在log级别.
这个时候统计就能保证时间复杂度在深度上是正确的允许我们乱搞.
然后是基础例题.
正解放下面,就是点分治之后暴力.
这里有两种暴力方法,第二种比较巧,用两个指针跳去找某个值.
具体都写在里面了,(第一种注释了).
#include<bits/stdc++.h>
typedef long long ll;
typedef unsigned long long ull;
#define qr qr()
#define ps push_back
#define fi first
#define se second
#define pa pair<int,int>
#define ve vector
using namespace std;
const int N=2e5+200,INF=1e7;
int n,m;
inline ll qr{
ll x=0;char ch=getchar();bool f=0;
while(ch>57||ch<48)f=(ch=='-')?1:0,ch=getchar();
while(ch>=48&&ch<=57)x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
return f?-x:x;
}
ve <pa> e[N];
int tot,vis[N],dis[N],mx[N],sz[N],bl[N];
int st[N],judge[INF],q[N],test[1500],query[1500];
int ans,sum,rt;
inline void add(int f,int t,int w){
e[f].ps({t,w});
e[t].ps({f,w});
}
void getrt(int u,int fa){
sz[u]=1,mx[u]=0;//每一次进来重置sz,mx.
for(auto i:e[u]){
int v=i.fi;
if(vis[v]||fa==v)continue;
getrt(v,u);
mx[u]=max(mx[u],sz[v]);
sz[u]+=sz[v];
}
mx[u]=max(mx[u],sum-sz[u]);
if(mx[rt]>mx[u])rt=u;
}
// void getdis(int u,int fa){
// st[++st[0]]=dis[u];
// for(auto i:e[u]){
// int v=i.fi;
// if(vis[v]||fa==v)continue;
// dis[v]=dis[u]+i.se;
// if(dis[v]>1e7)return;//总权值到达1e8级别,但查询只有1e7,减掉剩下部分.
// getdis(v,u);
// }
// }
void getdis(int u,int fa,int l){
bl[u]=l;
st[++tot]=u;
for(auto i:e[u]){
int v=i.fi;
if(vis[v]||fa==v)continue;
dis[v]=dis[u]+i.se;
getdis(v,u,l);
}
}
// void calc(int u){
// int p=0;
// for(auto i:e[u]){
// int v=i.fi;
// if(vis[v])continue;
// st[0]=0;dis[v]=i.se;//每次处理重置st,dis.
// getdis(v,u);
// for(int k=st[0];k;--k)//开栈拼凑
// for(int j=1;j<=m;++j)
// if(query[j]>=st[k])
// test[j]|=judge[query[j]-st[k]];
// for(int k=st[0];k;--k)
// q[++p]=st[k],judge[st[k]]=1;
// }
// for(int i=1;i<=p;++i)
// judge[q[i]]=0;
// }
bool cmp(int a,int b){
return dis[a]<dis[b];
}
void calc(int u){
tot=1;st[tot]=u;
dis[u]=0;
bl[u]=u;//这个赋值非常关键.
for(auto i:e[u]){
int v=i.fi;
if(vis[v])continue;
dis[v]=i.se;
getdis(v,u,v);
}
sort(st+1,st+tot+1,cmp);
for(int k=1;k<=m;++k){
if(test[k])continue;
int l=1,r=tot;
while(l<r){
if(dis[st[l]]+dis[st[r]]>query[k])--r;
else if(dis[st[l]]+dis[st[r]]<query[k])++l;
else if(bl[st[l]]==bl[st[r]]){
if(dis[st[r-1]]==dis[st[r]])--r;
else ++l;
}else {test[k]=1;break;}
}
}
}
void solve(int u){
vis[u]=1,calc(u);
for(auto i:e[u]){
int v=i.fi;
if(vis[v])continue;
sum=sz[v];mx[rt=0]=INF;
getrt(v,0);solve(rt);
}
}
void init(){
n=qr;m=qr;
for(int i=1;i<n;++i){
int u=qr,v=qr,w=qr;
add(u,v,w);
}
for(int i=1;i<=m;++i){
query[i]=qr;
if(!query[i])test[i]=1;
}
mx[rt]=sum=n;
getrt(1,0);
solve(rt);
for(int i=1;i<=m;++i){
if(test[i])printf("AYE\n");
else printf("NAY\n");
}
}
int main(){
freopen("in.in","r",stdin);
freopen("out.out","w",stdout);
// ios::sync_with_stdio(0);
// cin.tie(0);
// cout.tie(0);
init();
return 0;
}
点分树就先搁置吧.
https://www.cnblogs.com/shining-like-stars