[DS记录]CF526G Spiders Evil Plan

· · 个人记录

题意 : 给定一棵 n 个点的无根树,每条边有边权。

q 次询问,每次给出 x,y ,需要选择 y 条树上的路径,使这些路径形成一个包含点 x 的连通块,且连通块中包含的边权和最大。

------------ 先考虑单组询问。 - **定理** : 树有不超过 $2k$ 个叶子 $\Leftrightarrow$ 可以被 $k$ 条路径覆盖。 必要性显然,下证充分性。 以叶子为权,选取重心为根,可以保证每个分支内部都有不超过 $k$ 个叶子。 将这些叶子匹配起来,让每条路径都经过根。 现在,对于每个叶子,其到根的路径都被覆盖过,显然整棵树都被覆盖了。 现在,以点 $x$ 为根,问题等价于选取 $2y$ 个叶子是的向上的路径并最大。(注意根也可能是叶子) 这等价于带权长剖后选择长度前 $2y$ (或者 $2y-1$ )的长链。 接下来考虑多组询问。 能够发现,无论以何点为根,最长的长链端点必然可以是直径的端点。也就是说,选出的树形图必然包含直径的端点之一。 所以,我们只需要考虑根为直径端点的情况。 选出前 $2y-1$ (直径端点必然是叶子) 的长链后,可能并不包含点 $x$,需要做些调整。 设 $x$ 子树内最深点为 $t$。 有如下两种方案 : - 去掉第 $2y-1$ 条长链,然后将 $t$ 到根的路径加入树形图。 - 找到 $t$ 被包含在树形图内的最深祖先,将所在长链的后半段切掉。 容易使用倍增实现。 ```cpp #include<algorithm> #include<cstdio> #include<vector> #define pb push_back #define MaxN 100500 using namespace std; vector<int> g[MaxN],l[MaxN]; int n,dis[MaxN]; void pfs(int u) { for (int i=0,v;i<g[u].size();i++) if (!dis[v=g[u][i]]){ dis[v]=dis[u]+l[u][i]; pfs(v); } } struct Line{int u,v,len;}; bool cmpL(const Line &A,const Line &B) {return A.len>B.len;} struct Solver { int dis[MaxN],mp[MaxN],len[MaxN],f[20][MaxN]; void pfs1(int u) { for (int i=0,v;i<g[u].size();i++) if (!dis[v=g[u][i]]){ f[0][v]=u; dis[v]=dis[u]+l[u][i]; pfs1(v); if (len[u]<len[v]+l[u][i]) len[u]=len[mp[u]=v]+l[u][i]; } } Line s[MaxN]; int tn,id[MaxN]; void pfs2(int u,int tf) { if (!mp[u]){ s[++tn]=(Line){tf,u,dis[u]-dis[tf]}; return ; } pfs2(mp[u],tf); for (int i=0,v;i<g[u].size();i++) if (dis[v=g[u][i]]>dis[u]&&v!=mp[u]) pfs2(v,u); } void Init(int rt) { dis[0]=dis[rt]=1;pfs1(rt);pfs2(rt,0); sort(s+1,s+tn+1,cmpL); for (int i=1;i<=tn;i++){ s[i].len+=s[i-1].len; for (int p=s[i].v;p!=s[i].u;p=f[0][p]) id[p]=i; } for (int j=1;j<17;j++) for (int i=1;i<=n;i++) f[j][i]=f[j-1][f[j-1][i]]; } int get(int u,int lim) { int k=17; while(k--) while(id[f[k][u]]>lim) u=f[k][u]; return f[0][u]; } int qry(int u,int c) { if (c>tn)return s[tn].len; if (id[u]<=c)return s[c].len; int ret=s[c-1].len+dis[u]+len[u]-dis[get(u,c-1)]; int t=get(u,c); ret=max(ret,s[c].len+dis[u]+len[u]-dis[s[id[t]].v]); return ret; } }T1,T2; int q; int main() { scanf("%d%d",&n,&q); for (int i=1,u,v,c;i<n;i++){ scanf("%d%d%d",&u,&v,&c); g[u].pb(v);l[u].pb(c); g[v].pb(u);l[v].pb(c); } int tp=1; dis[1]=1;pfs(1); for (int i=1;i<=n;i++) if (dis[i]>dis[tp])tp=i; T1.Init(tp); for (int i=1;i<=n;i++)dis[i]=0; dis[tp]=1;pfs(tp); for (int i=1;i<=n;i++) if (dis[i]>dis[tp])tp=i; T2.Init(tp); for (int i=1,u,c,las=0;i<=q;i++){ scanf("%d%d",&u,&c); u=(u+las-1)%n+1; c=(c+las-1)%n+1; c=c*2-1; printf("%d\n",las=max(T1.qry(u,c),T2.qry(u,c))); }return 0; } ```