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. 使用寄存器点亮LED——2

    1. 项目:使用stm32寄存器点亮LED, 分别点亮红.绿.蓝3个灯. 2. 步骤 先新建个文件夹保存项目 再新建项目 将startup_stm32f10x_hd.s拷贝到该文件夹下 新建main. ...

  2. 【UE4】GAMES101 图形学作业4:贝塞尔曲线

    总览 Bézier 曲线是一种用于计算机图形学的参数曲线. 在本次作业中,你需要实现de Casteljau 算法来绘制由4 个控制点表示的Bézier 曲线(当你正确实现该算法时,你可以支持绘制由更 ...

  3. 【UE4】 补丁Patch 与 DLC

    概述 UE4 中主要使用 Project Launcher 来进行补丁和DLC的制作 补丁与 DLC 都需要基于某个版本而制作 补丁 与 DLC 最后以 Pak 形式表现, 补丁的 pak 可以重命名 ...

  4. LeetCode:“剑指 Offer”

    LeetCode:"剑指 Offer" 刷题小菜鸡,花了几天时间做了一遍 LeetCode 上给出的 "剑指 Offer" 在此做一下记录 LeetCode主页 ...

  5. 第五次Scrum Metting

    日期:2021年5月2日 会议主要内容概述:讨论前端进度,修改后端接口. 一.进度情况 组员 负责 两日内已完成的工作 后两日计划完成的工作 工作中遇到的困难 徐宇龙 后端 模板模块的实现及批量插入更 ...

  6. 【二食堂】Beta - Scrum Meeting 6

    Scrum Meeting 6 例会时间:5.19 18:30~18:50 进度情况 组员 当前进度 今日任务 李健 1. 实体标注的优化基本已经实现,后端有bug,还没有进行接口调用 issue 2 ...

  7. Spring Cloud Alibaba Nacos Config 的使用

    Spring Cloud Alibaba Nacos Config 的使用 一.需求 二.实现功能 1.加载 product-provider-dev.yaml 配置文件 2.实现配置的自动刷新 3. ...

  8. Python | 实现pdf文件分页

    不知道大家有没有遇到过这么一种情况,就比如一个pdf格式的电子书,我们经常浏览的是其中的一部分,而这电子书的页数很大,每当需要浏览时,就需要翻到对应的页码,就有点儿繁琐. 还有一些情况,比如,我们想分 ...

  9. Hadoop的HA(ZooKeeper)安装与部署

    非HA的安装步骤 https://www.cnblogs.com/live41/p/15467263.html 一.部署设定 1.服务器 c1   192.168.100.105    zk.name ...

  10. 就因为把int改成Integer,第2天被辞了

    本文节选自<设计模式就该这样学>之享元模式(Flyweight Pattern) 1 故事背景 一个程序员就因为改了生产环境上的一个方法参数,把int型改成了Integer类型,因为涉及到 ...