题解:P6782 [Ynoi2008] rplexq
更好的阅读体验
假设树的点数为
首先考虑一个复杂度和度数有关的做法。
这个是比较简单的。假设一个广义的
至于
我们对度数根号分治。假设阈值
这一部分在
接下来考虑度数
发现 LCA 为
看起来比较对的一个做法就是莫队。这样度数大的点数量不会超过
到这里我们发现寄完了。因为
但是我们发现,我们可以把大度点的前
考虑证明这个事情。假设一个点与它前
对于一个大小为
这样莫队的总点数就是
到这里我们可能会发现,一开始对度数进行根号分治已经不必要了。我们可以直接取阈值
至此,问题在
在实现中,我们发现,我们
实际操作中
#include<bits/stdc++.h>
#define endl '\n'
#define N 500006
#define M 5006
using namespace std;
using i64=long long;
int n,B,q,rt,bn,b[N],co[N],dfs_clock,f[N],dfn[N],sz[N],sum[N][4],c[N];
i64 ans[N],cnt;
vector<int> G[N],t[N]; vector<pair<int,int> > vec[N];
struct Ask {int l,r,u;} ask[N];
bool operator <(Ask x,Ask y)
{
int blx=(x.l-1)/B+1,bly=(y.l-1)/B+1;
return blx!=bly?blx<bly:(blx&1?x.r<y.r:x.r>y.r);
}
struct Block {
int tag[M],val[N];
void update(int l,int r,int x)
{
int bl=(l-1)/B+1,br=(r-1)/B+1;
if(bl==br){for(int i=l;i<=r;i++)val[i]+=x; return;}
int rb_l=min(n,bl*B),lb_r=(br-1)*B+1;
for(int i=bl+1;i<br;i++)tag[i]+=x;
for(int i=l;i<=rb_l;i++)val[i]+=x;
for(int i=lb_r;i<=r;i++)val[i]+=x;
}
int query(int k){return val[k]+tag[(k-1)/B+1];}
inline void update(int k,int x){update(k,n,x);}
inline int query(int l,int r){return query(r)-query(l-1);}
} ds;
void dfs1(int u,int fa)
{
sz[u]=1,f[u]=fa; vector<int> son;
for(int v:G[u])if(v!=fa)dfs1(v,u),sz[u]+=sz[v],son.push_back(v);
sort(son.begin(),son.end(),[](int x,int y) {
return sz[x]>sz[y];
});
G[u].swap(son);
}
void dfs2(int u){dfn[u]=++dfs_clock; for(int v:G[u])dfs2(v);}
void dfs3(int u,int col){b[++bn]=u,co[u]=col; for(int v:G[u])dfs3(v,col);}
inline i64 binom2(int x){return 1ll*x*(x-1)/2;}
inline int calc(int u){return ds.query(dfn[u],dfn[u]+sz[u]-1);}
inline void mo_add(int x){if(x)cnt+=c[x]++;}
inline void mo_del(int x){if(x)cnt-=--c[x];}
void solve_small()
{
for(int i=1;i<=n;i++)
{
ds.update(dfn[i],1);
for(auto [j,opt]:vec[i])
{
int u=ask[j].u,sz=G[u].size(); ans[j]+=opt*calc(u);
for(int k=0;k<3&&k<sz;k++)sum[j][k]+=opt*calc(G[u][k]);
}
}
for(int i=1;i<=q;i++)
{
ans[i]=binom2(ans[i]); int sz=G[ask[i].u].size();
for(int j=0;j<3&&j<sz;j++)ans[i]-=binom2(sum[i][j]);
}
}
void solve_big()
{
for(int i=1;i<=q;i++)
if(G[ask[i].u].size()>3)t[ask[i].u].push_back(i);
for(int u=1;u<=n;u++)if(t[u].size())
{
bn=0; int sz=G[u].size();
for(int i=3;i<sz;i++)dfs3(G[u][i],G[u][i]);
sort(b+1,b+1+bn);
for(int i:t[u])
{
auto &[l,r,_]=ask[i];
l=lower_bound(b+1,b+1+bn,l)-b,r=upper_bound(b+1,b+1+bn,r)-b-1;
}
sort(t[u].begin(),t[u].end(),[](int x,int y) {
return ask[x]<ask[y];
}),cnt=0; int lb=1,rb=0;
for(int i:t[u])
{
auto [l,r,_]=ask[i];
for(;lb>l;mo_add(co[b[--lb]])); for(;lb<l;mo_del(co[b[lb++]]));
for(;rb<r;mo_add(co[b[++rb]])); for(;rb>r;mo_del(co[b[rb--]]));
ans[i]-=cnt;
}
}
}
main()
{
scanf("%d%d%d",&n,&q,&rt),B=pow(n,0.5);
for(int i=1,u,v;i<n;i++)
scanf("%d%d",&u,&v),G[u].push_back(v),G[v].push_back(u);
dfs1(rt,0),dfs2(rt);
for(int i=1;i<=q;i++)
scanf("%d%d%d",&ask[i].l,&ask[i].r,&ask[i].u),
vec[ask[i].l-1].push_back({i,-1}),vec[ask[i].r].push_back({i,1});
solve_small(),solve_big();
for(int i=1;i<=q;i++)printf("%lld\n",ans[i]);
return 0;
}