这题之前被搬过。
考虑以
x
x
x为根,那么我们显然会选
k
k
k个叶子(
k
k
k的值取决于
x
x
x是否是叶子),使得它们到
x
x
x的路径的并长度最大。容易证明一个正确的贪心是以
x
x
x为根做长链剖分后取前
k
k
k大的链。
但是这样复杂度太高了,注意到我们一定会选直径的一端。那么我们分别以直径两端建树,取答案的
max
\max
max,求出依次选择的方案,如果前
k
k
k大的链覆盖了
x
x
x,那么答案显然一致,否则我们会在
x
x
x所在的子树中取一个叶子对应的链,删去另一个已选的叶子对应的链,可以讨论一下用线段树维护。
时间复杂度
O
(
(
n
+
q
)
log
n
)
\mathcal O((n+q)\log n)
O((n+q)logn)。
#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
#define FR first
#define SE second
#define end end2
using namespace std;
typedef pair<int,int> pr;
struct Edge {
int t,v,next;
Edge() {}
Edge(int a,int b,int c):t(a),v(b),next(c) {}
};
Edge e[200005];
int head[100005];
namespace Tree {
int dis[100005];
int dfs(int x,int fa) {
int ans=x;
for(int i=head[x];i;i=e[i].next)
if (e[i].t!=fa) {
int u=e[i].t;
dis[u]=dis[x]+e[i].v;
int t=dfs(u,x);
if (dis[t]>=dis[ans]) ans=t;
}
return ans;
}
}
struct SGT {
pr maxn[400000];
int addv[400000];
inline void pushdown(int o) {
if (addv[o]) {
addv[o*2]+=addv[o];maxn[o*2].FR+=addv[o];
addv[o*2+1]+=addv[o];maxn[o*2+1].FR+=addv[o];
addv[o]=0;
}
}
inline void pushup(int o) {
maxn[o]=max(maxn[o*2],maxn[o*2+1]);
}
void build(int l,int r,int o,int *fir) {
addv[o]=0;
if (l==r) maxn[o]=pr(fir[l],l);
else {
int m=((l+r)>>1);
build(l,m,o*2,fir);
build(m+1,r,o*2+1,fir);
pushup(o);
}
}
void update(int l,int r,int o,int lx,int rx,int p) {
if (l>=lx&&r<=rx) {
addv[o]+=p;
maxn[o].FR+=p;
}
else {
pushdown(o);
int m=((l+r)>>1);
if (m>=lx) update(l,m,o*2,lx,rx,p);
if (m<rx) update(m+1,r,o*2+1,lx,rx,p);
pushup(o);
}
}
pr query() {
return maxn[1];
}
};
struct Solve {
int rt,col[100005],col2[100005],fa[100005][20];
int maxd[100005],dis[100005],pv[100005];
bool leaf[100005];
int dfn[100005],end[100005],dfs_cnt;
int num[100005],fir[100005];
void dfs(int x) {
dfn[x]=dfs_cnt+1;
leaf[x]=1;
for(int i=head[x];i;i=e[i].next)
if (e[i].t!=fa[x][0]) {
leaf[x]=0;
int u=e[i].t;
fa[u][0]=x;
for(int j=1;j<20;j++) fa[u][j]=fa[fa[u][j-1]][j-1];
dis[u]=dis[x]+e[i].v;pv[u]=e[i].v;
dfs(u);
maxd[x]=max(maxd[x],maxd[u]+e[i].v);
}
if (leaf[x]) {
num[++dfs_cnt]=x;
fir[dfs_cnt]=dis[x];
}
end[x]=dfs_cnt;
}
SGT tr;
int val[100005],sum[100005],cur[100005];
void build(int t) {
rt=t;
dfs(rt);
tr.build(1,dfs_cnt,1,fir);
for(int i=1;i<=dfs_cnt;i++) {
pr t=tr.query();
val[i]=t.FR;sum[i]=sum[i-1]+val[i];
int x=num[t.SE];
cur[i]=x;
tr.update(1,dfs_cnt,1,dfn[x],end[x],-inf);
while (x!=rt&&!col[x]) {
tr.update(1,dfs_cnt,1,dfn[x],end[x],-pv[x]);
col[x]=i;
x=fa[x][0];
}
while (x!=rt&&!col2[x]) {
col2[x]=i;
x=fa[x][0];
}
}
}
int jump(int x,int d) {
for(int i=19;i>=0;i--)
if (col[fa[x][i]]>=d) x=fa[x][i];
return x;
}
int query(int x,int y) {
y=min(2*y-1,dfs_cnt);
int ans=sum[y];
if (col[x]>y) {
int u=fa[jump(x,y)][0];
ans+=maxd[x]+dis[x]-dis[u];
int s=val[y];
if (u!=rt&&(!col2[u]||col2[u]>y)) {
int v=cur[col[u]];
s=min(s,dis[v]-dis[u]);
}
ans-=s;
}
return ans;
}
} a,b;
int main() {
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<n;i++) {
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
e[2*i-1]=Edge(y,z,head[x]);
head[x]=2*i-1;
e[2*i]=Edge(x,z,head[y]);
head[y]=2*i;
}
int rt1=Tree::dfs(1,0);
Tree::dis[rt1]=0;
int rt2=Tree::dfs(rt1,0);
a.build(rt1);
b.build(rt2);
int lastans=0;
for(int i=1;i<=m;i++) {
int x,y;
scanf("%d%d",&x,&y);
x=(x+lastans-1)%n+1;y=(y+lastans-1)%n+1;
if (n==1) {
puts("0");
continue;
}
lastans=max(a.query(x,y),b.query(x,y));
printf("%d\n",lastans);
}
return 0;
}