将其以$x$为根建树,并定义$k$的点权$w_{k}$为$k$到其父亲的边边权(特别的$w_{x}=0$),那么问题也可以看作选一个包含$x$的点集,满足其的导出子图连通且边集可以被划分为$y$条路径,并最大化点权和
性质1:边集可以被划分为$y$条路径,当且仅当度为1的节点不超过$2y$个
必要性:一条路径上至多有两个度为1的节点,那么$y$条路径也即至多有$2y$个
充分性:将所有叶子按照dfs序排序,并将第$4k+0/1$个叶子向第$4k+2/3$个叶子匹配,考虑每一个子树内存在叶子的节点,相当于要求某个区间内的叶子存在向子树外的边,简单分析可以发现上述构造总存在这样的边,即合法
对其长链剖分,定义长儿子为子树带权深度最深的儿子(多个任取),并以此将原树划分为若干条链
记$L_{i}$为第$i$条链的点集且$W_{i}=\sum_{x\in L_{i}}w_{x}$,显然$L_{i}$两两不交且并集恰为点集$V$,再将其按照$W_{i}$从大到小排序(相同按照链顶深度从小到大排序),并在最后补上若干个$L_{i}=\empty$
结论1:若$S=\bigcup_{i=1}^{2y}L_{i}$的导出子图中$x$的度数不为1,则答案为$\sum_{i=1}^{2y}W_{i}$;否则,设$k$为$S$中与$x$相邻的节点,则答案为$\sum_{i=1}^{2y-1}W_{i}+W_{pos}$(其中$pos=\min_{L_{i}\cap sub_{k}=\empty}i$)
下面,来证明以下上述结论的正确性(或感性理解后直接跳至这里):
引理1:若$L_{i}$链顶的父亲是$L_{j}$链顶的祖先(严格),则$i\le j$
性质2:存在一个取到最大点权和的点集$S$,使得$S$是若干个$L_{i}$的并
任取一个取到最大点权和的点集$S$,若其不为若干个$L_{i}$的并,则必然存在$L_{i}$满足$L_{i}\not\subseteq S$且$L_{i}\cap S\ne \empty$(注意到$S\subseteq \bigcup L_{i}=V$),那么取其中最小的$i$,并做如下变换:
令$x$为$L_{i}$中最深的点满足其在$S$中,并任取$x$子树中的一个叶子$y$,将$y$不断向上移动直至点$z$满足$z$有两个儿子$\in S$或$z=x$,然后删除$y$到$z$路径上的点(包括$y$,不包括$z$),再选上$L_{i}$中$\not\in S$的部分
此时不改变度为1的节点数且点权和单调不降,因此$S$仍取到最大点权和且合法
另一方面,影响的仅有$x$子树内,根据引理1显然不会影响$j<i$的$L_{j}$与$S$的关系,同时这使得$L_{i}\subseteq S$,那么重复此过程即可使得$S$是若干个$L_{i}$的并
引理2:若$S=\bigcup_{i\in S'}L_{i}$且$\forall i\in S',L_{i}\ne \empty$,则$S$中至少存在$|S'|$个度为1的点
性质3:$\forall k\ge 1,\bigcup_{i=1}^{k}L_{i}$的导出子图连通且除$x$以外恰有$k$个度为1的点
归纳此结论成立,根据引理1$L_{1}$必然是包含$x$的链,那么显然成立
考虑加入$L_{k+1}$,同样根据引理1$L_{k+1}$链顶的父亲必然要在$\bigcup_{i=1}^{k}L_{i}$中(否则必然在后面即矛盾),即证明其连通,同时也即链顶度数不为1,那么仅新增一个度为1的节点(链尾)
(如果该父亲的度数为1,不难发现其必然是$x$,因此也不影响)
综上,来考虑原结论——
对于结论前半部分,性质2和引理2说明了答案上界为$\sum_{i=1}^{2y}W_{i}$,同时根据性质3和条件($x$度数不为1)该上界可以被$\bigcup_{i=1}^{2y}L_{i}$取到,因此即为答案
对于结论后半部分,注意到若选了$2y$条链,那么$x$的度数必然不能为1,再根据$pos$的最小性也即链不能都选在$L_{pos}$之前,因此$\sum_{i=1}^{2y-1}W_{i}+W_{pos}$为答案上界且可以被$\bigcup_{i=1}^{2y-1}L_{i}\cup L_{pos}$取到,即为答案
但$x$并不固定,因此长链的划分也不固定,需要每次询问重新建树,无法通过
考虑优化,任取一条(带权)直径$(a,b)$,不妨假设其中$a$距离$x$较远,那么根据直径的性质,不难得到$a$也是距离$x$最远的点(之一)
引理3:存在一个取到最大点权和的点集$S$,使得$a\in S$
由此,问题可以看作$x=a$且强制选择$x$的答案
若没有选择$x$的限制,根据结论1的构造答案集合可以为$S=\bigcup_{i=1}^{2y-1}L_{i}$(注意$a$一定是叶子)
若$x\in S$,即$S$本身也满足条件,那么显然取到最大,答案也即$\sum_{i=1}^{2y-1}W_{i}$
若$x\not\in S$,强制选择$x$可以看作将$x$的点权加上$\infty$,那么长儿子的变化即将$x$到$a$路径上(包括$a$,不包括$x$)的点长儿子替换为其链上的儿子,长链的变化也即将其与$x$到$a$路径上的交删除(并新增一条长链)
(注意这里加上$\infty$只是为了方便理解长儿子/长链形式上的变化)
由于$x$的点权足够大,一定会先选上新增的这条链,并再选此时最长的$2y-2$条链即可
性质4:对于原来$L_{1},L_{2},..,L_{2y-2}$,仅有$x$到$a$路径有交且链顶最深的$L_{pos}$可能被"顶替"
令$L'_{i}$为变化后的$L_{i}$,$W'_{i}$为对应权值,由于只有删除,即$W'_{i}\le W_{i}$,不难得到$\forall 1\le i\le 2y-2$不被"顶替"的充分条件是$W_{i}=W'_{i}$或$W'_{i}\ge W_{2y-2}$
进而考虑$W_{i}>W'_{i}$的链,即其与$x$到$a$路径有交,令$x$为$L'_{i}$链顶的父亲,在长儿子变化之前$L'_{i}$的链顶即是$x$的长儿子,同时$x$显然也是$L_{pos}$的链顶的祖先,因此$W'_{i}\ge W_{pos}\ge W_{2y-2}$
(特别的,若$pos\ge 2y-1$,即其中不存在$W_{i}>W'_{i}$的链)
进而考虑替换$L_{pos}$的链,如果$L_{2y-1}$与$x$到$a$路径没有交显然是$L_{2y-1}$
若$L_{2y-1}$与$x$到$a$路径有交,类似上述证明一定有$W'_{pos}\ge W_{2y-1}$,即剩下的链都无法替换$L_{pos}$,因此不妨直接比较$W'_{pos}$和$W_{2y-1}$并选择即可
具体实现中,需要维护以下信息:
1.每一条长链的链顶、链尾和点权(前缀)和
2.每一个点深度和所在链的排名
3.倍增维护其到其$2^{i}$祖先这条路径上排名最低的点(指所在链排名)的排名
由此,先根据信息2判断$x\in S$,若$x\not\in S$再倍增找到其第一个排名$\le 2y-2$的祖先,将这个祖先到其路径上的点补上,并加上$\max(W_{2y-1}-$链剩余部分$,0)$即可
时间复杂度为$o(n\log n+q\log n)$,可以通过
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 100005 4 struct Edge{ 5 int nex,to,len; 6 }edge[N<<1]; 7 int n,m,E,x,y,z,ans,head[N],dep[N],tmp[N]; 8 struct Chain{ 9 int top,tail,len; 10 bool operator < (const Chain &k)const{ 11 return (len>k.len)||(len==k.len)&&(tmp[len]<tmp[k.len]); 12 } 13 }; 14 void add(int x,int y,int z){ 15 edge[E]=Edge{head[x],y,z}; 16 head[x]=E++; 17 } 18 void dfs(int k,int fa,int s){ 19 dep[k]=s; 20 for(int i=head[k];i!=-1;i=edge[i].nex) 21 if (edge[i].to!=fa)dfs(edge[i].to,k,s+edge[i].len); 22 } 23 struct Data{ 24 int rt,w[N],dep[N],leaf[N],bl[N],sum[N],f[N][20],mn[N][20]; 25 vector<Chain>v; 26 void dfs(int k,int fa,int s){ 27 w[k]=s-dep[fa],dep[k]=s,f[k][0]=fa; 28 for(int i=1;i<20;i++)f[k][i]=f[f[k][i-1]][i-1]; 29 leaf[k]=k; 30 for(int i=head[k];i!=-1;i=edge[i].nex) 31 if (edge[i].to!=fa){ 32 dfs(edge[i].to,k,s+edge[i].len); 33 int x=leaf[edge[i].to]; 34 if ((!leaf[k])||(dep[leaf[k]]<dep[x]))leaf[k]=x; 35 } 36 for(int i=head[k];i!=-1;i=edge[i].nex) 37 if ((edge[i].to!=fa)&&(leaf[edge[i].to]!=leaf[k])){ 38 int x=edge[i].to,y=leaf[edge[i].to]; 39 v.push_back(Chain{x,y,dep[y]-dep[f[x][0]]}); 40 } 41 } 42 void get_mn(int k,int fa){ 43 mn[k][0]=bl[k]; 44 for(int i=1;i<20;i++)mn[k][i]=min(mn[k][i-1],mn[f[k][i-1]][i-1]); 45 for(int i=head[k];i!=-1;i=edge[i].nex) 46 if (edge[i].to!=fa)get_mn(edge[i].to,k); 47 } 48 void build(int k){ 49 rt=k; 50 dfs(rt,0,0); 51 v.push_back(Chain{rt,leaf[rt],dep[leaf[rt]]}); 52 memcpy(tmp,dep,sizeof(tmp)); 53 sort(v.begin(),v.end()); 54 for(int i=0;i<v.size();i++){ 55 sum[i+1]=sum[i]+v[i].len; 56 for(int j=v[i].tail;j!=v[i].top;j=f[j][0])bl[j]=i+1; 57 bl[v[i].top]=i+1; 58 } 59 get_mn(rt,0); 60 } 61 int query(int x,int y){ 62 if (bl[x]<(y<<1))return sum[min((y<<1)-1,(int)v.size())]; 63 int z=x; 64 for(int i=19;i>=0;i--) 65 if (mn[z][i]>(y<<1)-2)z=f[z][i]; 66 if (!z)return sum[(y<<1)-2]+(dep[leaf[x]]-dep[z]); 67 return sum[(y<<1)-2]+(dep[leaf[x]]-dep[z])+max(v[(y<<1)-2].len-(dep[v[bl[z]-1].tail]-dep[z]),0); 68 } 69 }Ta,Tb; 70 int main(){ 71 scanf("%d%d",&n,&m); 72 memset(head,-1,sizeof(head)); 73 for(int i=1;i<n;i++){ 74 scanf("%d%d%d",&x,&y,&z); 75 add(x,y,z),add(y,x,z); 76 } 77 dfs(1,0,0); 78 x=y=1; 79 for(int i=2;i<=n;i++) 80 if (dep[x]<dep[i])x=i; 81 dfs(x,0,0); 82 for(int i=2;i<=n;i++) 83 if (dep[y]<dep[i])y=i; 84 Ta.build(x),Tb.build(y); 85 for(int i=1;i<=m;i++){ 86 scanf("%d%d",&x,&y); 87 x=(x+ans-1)%n+1,y=(y+ans-1)%n+1; 88 if (Ta.dep[x]>Tb.dep[x])ans=Ta.query(x,y); 89 else ans=Tb.query(x,y); 90 printf("%d\n",ans); 91 } 92 return 0; 93 }View Code