ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

[cf526G]Spiders Evil Plan

2021-10-01 08:32:16  阅读:173  来源: 互联网

标签:cf526G 点权 路径 pos Evil 2y bigcup 链顶 Spiders


将其以$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

 

标签:cf526G,点权,路径,pos,Evil,2y,bigcup,链顶,Spiders
来源: https://www.cnblogs.com/PYWBKTDA/p/15358698.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有