Codeforces 题目传送门 & 洛谷题目传送门

%%%%% 这题也太神了吧 storz 57072 %%%%%

首先容易注意到我们选择的这 \(y\) 条路径的端点一定是叶子节点,否则我们总可以将其调整到叶子节点并使答案不会更劣,并且如果非必须(\(2y\le\) 树中叶子节点的个数),我们选择的这 \(y\) 个路径的 \(2y\) 个端点一定两两不相同,否则我们还是可以调整重复的叶子节点的位置使答案不变劣。

其次我们还可以发现,对于固定的 \(2y\) 个叶子节点,我们总存在一种选法使得这 \(y\) 个路径的并集就是这 \(2y\) 个节点的虚树,证明应该不难,大概归纳一下就行了?这里就不再赘述。特判掉 \(2y>\) 树在叶子节点个数的情况,题目就等价于求一个包含 \(x\) 的含 \(2y\) 个叶子节点的虚树,使得虚树中边权之和尽可能大。我们考虑以 \(x\) 为根,先不考虑“虚树必须包含 \(x\)”这个条件,即我们假设要求 \(x\) 与这 \(2y\) 个叶子节点共同的虚树,显然这个集合就等于这 \(2y\) 个叶子节点到根节点路径的并集,也就是说我们要选 \(2y\) 个叶子节点使得它们到根节点路径的并集中边权和尽可能大。这似乎看起来有些熟悉?……不就 BZOJ3252 攻略吗?直接长链剖分一遍排个序即可。只不过这边要特判掉 \(x\) 本身就是叶子节点的情况,因为显然 \(x\) 必须被选入这 \(2y\) 个叶子节点中,故我们还需额外选出 \(2y-1\) 个叶子节点 instead of \(2y\) 个叶子节点。加上“虚树必须包含 \(x\)”这个条件也不困难,不难发现出问题的情况只有一种可能,那就是 \(x\) 本身不是叶子节点,并且选择的 \(2y\) 的叶子节点全在 \(x\) 的同一子树中,那根据贪心的思想,我们肯定会牺牲权值最小的长链,并加入叶子节点属于 \(x\) 的其他子树中权值最大的长链,这个随便搞搞就行了,至此我们解决了单词询问的情况。

接下来考虑多组询问的情况,不难发现上述算法的瓶颈在于每次询问都要重新以 \(x\) 为根搞一遍长链剖分,而长链剖分这类数据结构也不支持可持久化什么的,因此该算法也无法直接优化。那有什么办法呢?不妨来找找性质罢,不难发现在选择的 \(2y\) 个叶节点中,总有一个最特殊的节点——那就是离 \(x\) 最远的节点,因为这个节点不论怎样也不可能被删除(每次最多删除一个节点,而我们选择的节点数 \(\ge 2\))。而根据树的直径的性质,该点一定是树的直径的一个端点,因此我们考虑着眼于树的直径上,我们对于树的直径的两个端点 \(u,v\) 分别询问以下事情:求选择 \(2y\) 个叶子节点,其中一个是 \(u\)(或 \(v\)),并且它们的虚树包含 \(x\),它们虚树边权之和的最大值。显然我们只需在两个方案中取个较大值即可。那么这个最大值怎么求呢?不妨以包含 \(u\) 的部分举例,我们还是考虑以 \(u\) 为根,显然对于固定的另外 \(2y-1\) 个叶子节点的集合 \(\{x_1,x_2,\cdots,x_{2k-1}\}\),它们与 \(u\) 的虚树也一定是这 \(2k-1\) 个节点到 \(u\) 路径的并集。如果不考虑“必须包含 \(x\)”这个条件,那依旧一遍长链剖分就可以搞定。加上这个条件怎么办呢?还是考虑先按照不必须包含 \(x\) 的方案来选择叶子节点,然后在此基础上进行调整,记 \(rk_x\) 为对于 \(x\) 节点所在长链,其链上所有边权值之和在所有长链中从大到小排名是多少。如果 \(rk_x\le 2y-1\),那 \(x\) 已经被包含入这 \(2y\) 个叶子节点的虚树中了,就不用再调整了,否则调整方法只可能有以下两种:

  1. 删去已经选择的 \(2y-1\) 个长链中,权值最小的长链(设其权值为 \(val\)),并打通 \(x\) 子树内深度最大的叶子节点 \(w\) 到根节点的路径,设 \(x\) 到根节点路径上第一个 \(rk\le 2y-2\) 的节点为 \(z\),那显然打通这条路径权值的增量为 \(dis_{w}-dis_z\),其中 \(dis_i\) 为根节点到 \(i\) 路径上权值之和,总增量为 \(\Delta=-val+dis_w-dis_z\)。
  2. 记设 \(x\) 到根节点路径上第一个 \(rk\le 2y-1\) 的节点为 \(t\),如果 \(t\) 子树中只有一个叶节点被选择,那么我们可以索性把 \(t\) 子树内原来选择的边直接去掉,取而代之的是连接 \(t\) 与 \(x\) 子树内深度最大的节点 \(w\) 的路径上的边,这部分的增量为 \(\Delta=-mxdep_t+mxdep_x\)。

求一个点到根节点上第一个 \(rk\le t\) 的点可以用倍增,总复杂度 \(n\log n\),因为有个倍增的 \(\log\)。

#include <bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define fill0(a) memset(a,0,sizeof(a))
#define fill1(a) memset(a,-1,sizeof(a))
#define fillbig(a) memset(a,63,sizeof(a))
#define pb push_back
#define ppb pop_back
#define mp make_pair
template<typename T1,typename T2> void chkmin(T1 &x,T2 y){if(x>y) x=y;}
template<typename T1,typename T2> void chkmax(T1 &x,T2 y){if(x<y) x=y;}
typedef pair<int,int> pii;
typedef long long ll;
typedef unsigned int u32;
typedef unsigned long long u64;
namespace fastio{
#define FILE_SIZE 1<<23
char rbuf[FILE_SIZE],*p1=rbuf,*p2=rbuf,wbuf[FILE_SIZE],*p3=wbuf;
inline char getc(){return p1==p2&&(p2=(p1=rbuf)+fread(rbuf,1,FILE_SIZE,stdin),p1==p2)?-1:*p1++;}
inline void putc(char x){(*p3++=x);}
template<typename T> void read(T &x){
x=0;char c=getchar();T neg=0;
while(!isdigit(c)) neg|=!(c^'-'),c=getchar();
while(isdigit(c)) x=(x<<3)+(x<<1)+(c^48),c=getchar();
if(neg) x=(~x)+1;
}
template<typename T> void recursive_print(T x){if(!x) return;recursive_print(x/10);putc(x%10^48);}
template<typename T> void print(T x){if(!x) putc('0');if(x<0) putc('-'),x=~x+1;recursive_print(x);}
void print_final(){fwrite(wbuf,1,p3-wbuf,stdout);}
}
const int MAXN=1e5;
const int LOG_N=17;
int n,qu,hd[MAXN+5],to[MAXN*2+5],nxt[MAXN*2+5],val[MAXN*2+5],ec;
void adde(int u,int v,int w){to[++ec]=v;val[ec]=w;nxt[ec]=hd[u];hd[u]=ec;}
namespace dia{
int dis1[MAXN+5],dis2[MAXN+5],rt1=1,rt2=1;
void dfs1(int x,int f){
for(int e=hd[x];e;e=nxt[e]){
int y=to[e],z=val[e];if(y==f) continue;
dis1[y]=dis1[x]+z;dfs1(y,x);
}
}
void dfs2(int x,int f){
for(int e=hd[x];e;e=nxt[e]){
int y=to[e],z=val[e];if(y==f) continue;
dis2[y]=dis2[x]+z;dfs2(y,x);
}
}
void find_dia(){
dfs1(1,0);for(int i=1;i<=n;i++) if(dis1[i]>dis1[rt1]) rt1=i;
dfs2(rt1,0);for(int i=1;i<=n;i++) if(dis2[i]>dis2[rt2]) rt2=i;
}
}
struct solver{
int rt,dep[MAXN+5],mxdep[MAXN+5],dson[MAXN+5],top[MAXN+5];
int fa[MAXN+5][LOG_N+2],rnk[MAXN+5];
pii chain[MAXN+5];int chain_n=0,sum[MAXN+5];
void dfs0(int x,int f){
fa[x][0]=f;
for(int e=hd[x];e;e=nxt[e]){
int y=to[e],z=val[e];if(y==f) continue;
dep[y]=mxdep[y]=dep[x]+z;dfs0(y,x);
if(mxdep[y]>mxdep[x]) mxdep[x]=mxdep[y],dson[x]=y;
}
}
void dfs1(int x,int tp){
top[x]=tp;if(dson[x]) dfs1(dson[x],tp);
for(int e=hd[x];e;e=nxt[e]){
int y=to[e];if(y==fa[x][0]||y==dson[x]) continue;
dfs1(y,y);
}
}
void init(){
dfs0(rt,0);dfs1(rt,rt);
for(int i=1;i<=LOG_N;i++) for(int j=1;j<=n;j++)
fa[j][i]=fa[fa[j][i-1]][i-1];
for(int i=1;i<=n;i++) if(top[i]==i)
chain[++chain_n]=mp(mxdep[i]-dep[fa[i][0]],i);
sort(chain+1,chain+chain_n+1);reverse(chain+1,chain+chain_n+1);
// for(int i=1;i<=chain_n;i++) printf("%d %d\n",chain[i].fi,chain[i].se);
for(int i=1;i<=chain_n;i++) rnk[chain[i].se]=i;
for(int i=1;i<=n;i++) rnk[i]=rnk[top[i]];
for(int i=1;i<=chain_n;i++) sum[i]=sum[i-1]+chain[i].fi;
}
int getfst(int x,int rk){
for(int i=LOG_N;~i;i--) if(rnk[fa[x][i]]>rk) x=fa[x][i];
return fa[x][0];
}
int query(int x,int y){
y=(y<<1)-1;if(y>chain_n) return sum[chain_n];
if(rnk[x]<=y) return sum[y];int anc=getfst(x,y);
// printf("anc=%d\n",anc);
return max(sum[y-1]+mxdep[x]-dep[getfst(x,y-1)],sum[y]-mxdep[anc]+mxdep[x]);
}
} t[2];
int main(){
scanf("%d%d",&n,&qu);
for(int i=1,u,v,w;i<n;i++){scanf("%d%d%d",&u,&v,&w);adde(u,v,w);adde(v,u,w);}
dia::find_dia();t[0].rt=dia::rt1;t[1].rt=dia::rt2;t[0].init();t[1].init();
int ans=0;while(qu--){
int x,y;scanf("%d%d",&x,&y);x=(x+ans-1)%n+1;y=(y+ans-1)%n+1;
// printf("real %d %d\n",x,y);
printf("%d\n",ans=max(t[0].query(x,y),t[1].query(x,y)));
}
return 0;
}

Codeforces 526G - Spiders Evil Plan(长链剖分+直径+找性质)的更多相关文章

  1. CF Contest 526 G. Spiders Evil Plan 长链剖分维护贪心

    LINK:Spiders Evil Plan 非常巧妙的题目. 选出k条边使得这k条边的路径覆盖x且覆盖的边的边权和最大. 类似于桥那道题还是选择2k个点 覆盖x那么以x为根做长链剖分即可. 不过这样 ...

  2. Codeforces 526G Spiders Evil Plan

    由于做的时候看的是中文题面,第一遍写就被卡题意了:还以为每一条都要过x,那么就是一道动态树根选择2y个叶子的奇怪题目 交完0分gg,才发现题目看错了╮(╯▽╰)╭ the node containin ...

  3. 2019.01.08 codeforces 1009F. Dominant Indices(长链剖分)

    传送门 长链剖分模板题. 题意:给出一棵树,设fi,jf_{i,j}fi,j​表示iii的子树中距离点iii距离为jjj的点的个数,现在对于每个点iii要求出使得fif_ifi​取得最大值的那个jjj ...

  4. Codeforces 1009 F. Dominant Indices(长链剖分/树上启发式合并)

    F. Dominant Indices 题意: 给一颗无向树,根为1.对于每个节点,求其子树中,哪个距离下的节点数量最多.数量相同时,取较小的那个距离. 题目: 这类题一般的做法是树上的启发式合并,复 ...

  5. Codeforces 1413F - Roads and Ramen(树的直径+找性质)

    Codeforces 题目传送门 & 洛谷题目传送门 其实是一道还算一般的题罢--大概是最近刷长链剖分,被某道长链剖分与直径结合的题爆踩之后就点开了这题. 本题的难点就在于看出一个性质:最长路 ...

  6. 2019.01.06 vijos lxhgww的奇思妙想(长链剖分)

    传送门 长链剖分模板题. 题意简述:允许O(nlogn)O(nlog_n)O(nlogn​)预处理,让你支持O(1)O(1)O(1)查找任意一个点的kkk级祖先. 思路:因为要O(1)O(1)O(1) ...

  7. 【CF526G】Spiders Evil Plan(贪心)

    [CF526G]Spiders Evil Plan(贪心) 题面 洛谷 CodeForces 给定一棵树,要求选择\(y\)条链,满足被链覆盖的所有点在树上联通,且\(x\)必定在联通块中. 对于每次 ...

  8. CF 1009 F Dominant Indices —— 长链剖分+指针

    题目:http://codeforces.com/contest/1009/problem/F 也可以用 dsu on tree 的做法,全局记录一个 dep,然后放进堆里,因为字典序要最小,所以再记 ...

  9. CF1009F Dominant Indices 长链剖分

    题目传送门 https://codeforces.com/contest/1009/problem/F 题解 长链剖分的板子吧. 令 \(dp[x][i]\) 表示 \(x\) 的子树中的深度为 \( ...

随机推荐

  1. C++ 与 Visual Studio 2022 和 WSL(五)——WSL2

    Build and Debug C++ with WSL 2 Distributions and Visual Studio 2022 References Build and Debug C++ w ...

  2. scala基础篇 使用getter和setter方法而不使用public的情形

    主要是基于2种情形 1) 提供读只取/只写入方法,不能随意读写 2)做赋值时变量控制,比如设定值的区间范围等 例子: object test{ def main(args: Array[String] ...

  3. eclipse javase版安装插件开发web项目

    最近学习开发javaweb,但是安装的却是java se版的eclipse,但其无法新建web项目,即找不到Dynamic Web.所以需要下载相应插件.以下为操作过程. 1. 在联网的情况下,打开e ...

  4. Noip模拟29(瞎眼忌) 2021.8.3

    T1 最长不下降子序列 在此记录自己的瞎眼... 考场上像一个傻$der$,自己为了防范上升序列和不下降序列的不同特意的造了一组$hack$数据来卡自己:(第一行是序列长度,第二行是序列) 6 1 5 ...

  5. linux cut

    参考:Linux cut 命令详解_Linux_脚本之家 (jb51.net) 参考:cut命令_Linux cut 命令用法详解:连接文件并打印到标准输出设备上 (linuxde.net)

  6. 链表中倒数第K个结点 牛客网 剑指Offer

    链表中倒数第K个结点 牛客网 剑指Offer 题目描述 输入一个链表,输出该链表中倒数第k个结点. # class ListNode: # def __init__(self, x): # self. ...

  7. 前端面试手写代码——call、apply、bind

    1 call.apply.bind 用法及对比 1.1 Function.prototype 三者都是Function原型上的方法,所有函数都能调用它们 Function.prototype.call ...

  8. IELTS6 2020.7 Translation

    原文 <三国演义>(The Romance of the ThreeKingdoms)是中国一部著名的历史小说,写于十四世纪.这部文学作品以三国时期的历史为背景,描写了从公元二世纪下半叶到 ...

  9. (四)php连接apache ,使用php-fpm方式

    上面各篇记录了编译安装lamp的各个部分,下面主要解决php和apache的连接问题.通过 php-fpm 连接. 连接前环境检查: php -v PHP 5.6.30 (cli) (built: O ...

  10. 装了这几个IDEA插件,基本上一站式开发了!

    前言 前几天有社区小伙伴私聊我,问我都用哪些IDEA插件,我的IDEA的主题看起来不错. 作为一个开源作者,每周要code大量的代码,提升日常工作效率是我一直追求的,在众多的IDEA插件中,我独钟爱这 ...