题意:
给出一颗树,每次选中m个点,对于树上任意一个点,会被其最近的一个选中点包含(相同有编号小优先),求每个选中点包含了多少个点。
分析:
之前写过两次都没写博客。。
结果复习板题的时候,连题意都不知道。。。
方法就是虚数板子
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#define SF scanf
#define PF printf
#define MAXN 300010
#define INF 0x3FFFFFFF
using namespace std;
typedef pair<int,int> pii;
int dfn[MAXN],ncnt,Q;
int dep[MAXN],siz[MAXN],ans[MAXN],flag[MAXN];
int fa[MAXN][20];
vector<int> a[MAXN],son[MAXN];
void dfs(int x,int f=0){
dep[x]=dep[f]+1;
fa[x][0]=f;
for(int i=1;i<20;i++)
fa[x][i]=fa[fa[x][i-1]][i-1];
dfn[x]=++ncnt;
siz[x]=1;
for(int i=0;i<int(a[x].size());i++){
int u=a[x][i];
if(u==f)
continue;
dfs(u,x);
siz[x]+=siz[u];
}
}
int find_child(int x,int u){
for(int i=19;i>=0;i--)
if(dep[fa[u][i]]>dep[x])
u=fa[u][i];
return u;
}
pii near[MAXN];
void get_near(int x){
if(flag[x]==Q)
near[x]=make_pair(0,x);
else
near[x]=make_pair(INF,0);
for(int i=0;i<int(son[x].size());i++){
int u=son[x][i];
get_near(u);
pii res=near[u];
res.first+=(dep[u]-dep[x]);
near[x]=min(near[x],res);
}
}
void get_near(int x,pii upd){
near[x]=min(near[x],upd);
for(int i=0;i<int(son[x].size());i++){
int u=son[x][i];
pii upd1=near[x];
upd1.first+=(dep[u]-dep[x]);
get_near(u,upd1);
}
}
void calc(int x){
int siz1=siz[x];
for(int i=0;i<int(son[x].size());i++){
int u=son[x][i];
calc(u);
int sonc=find_child(x,u);
siz1-=siz[sonc];
int ax=near[u].second,bx=near[x].second;
if(ax==bx){
ans[bx]+=(siz[sonc]-siz[u]);
continue;
}
int tp=u;
int q=near[u].first;
int p=near[x].first;
int totlen=p+q+dep[u]-dep[x];
for(int i=19;i>=0;i--){
int v=fa[tp][i];
if(dep[v]>dep[x]&&(dep[u]-dep[v]+q)*2<totlen)
tp=v;
}
if(totlen%2==0&&ax<bx&&(dep[u]-dep[fa[tp][0]]+q)*2<=totlen)
tp=fa[tp][0];
ans[ax]+=(siz[tp]-siz[u]);
ans[bx]+=(siz[sonc]-siz[tp]);
}
ans[near[x].second]+=siz1;
}
void solve(int rt){
get_near(rt);
get_near(rt,near[rt]);
ans[near[rt].second]+=(siz[1]-siz[rt]);
calc(rt);
}
bool sort_by_dfn(int x,int y){
return dfn[x]<dfn[y];
}
int lca(int u,int v){
if(dep[u]<dep[v])
swap(u,v);
for(int i=19;i>=0;i--)
if(dep[fa[u][i]]>=dep[v])
u=fa[u][i];
if(u==v)
return u;
for(int i=19;i>=0;i--)
if(fa[u][i]!=fa[v][i]){
u=fa[u][i];
v=fa[v][i];
}
return fa[u][0];
}
int n,u,v,q,tot,rt;
int b[MAXN],id[MAXN],st[MAXN],tp;
void Print(int x){
PF("%d(%d[%d,%d]) ",x,flag[x]==Q,near[x].first,near[x].second);
for(int i=0;i<int(son[x].size());i++)
Print(son[x][i]);
}
int main(){
SF("%d",&n);
for(int i=1;i<n;i++){
SF("%d%d",&u,&v);
a[u].push_back(v);
a[v].push_back(u);
}
dfs(1);
SF("%d",&q);
for(int i=1;i<=q;i++){
SF("%d",&tot);
Q++;
for(int j=1;j<=tot;j++){
SF("%d",&b[j]);
id[j]=b[j];
flag[b[j]]=Q;
}
sort(b+1,b+1+tot,sort_by_dfn);
tp=0;
st[++tp]=b[1];
son[b[1]].clear();
for(int j=2;j<=tot;j++){
int nx=lca(b[j],st[tp]);
while(tp>0&&dep[st[tp]]>dep[nx]){
rt=st[tp--];
if(tp==0||dep[st[tp]]<dep[nx]){
st[++tp]=nx;
son[nx].clear();
}
son[st[tp]].push_back(rt);
}
st[++tp]=b[j];
son[b[j]].clear();
}
while(tp){
rt=st[tp--];
if(tp)
son[st[tp]].push_back(rt);
}
for(int j=1;j<=tot;j++)
ans[id[j]]=0;
solve(rt);
// Print(rt);
for(int j=1;j<=tot;j++)
PF("%d ",ans[id[j]]);
PF("\n");
}
}