6380. 【NOIP2019模拟2019.10.06】小w与最长路(path)
题目
题目大意
给你一棵树,对于每一条边,求删去这条边之后,再用一条边(自己定)连接两个连通块,形成的树的直径最小是多少。
正解
首先,将这棵树的直径给找出来。显然,如果删去的边不在直径上,那么答案就是直径。
接下来考虑删去的边在直径上的情况。
自己连的边应该要是两棵树的直径的中点(中点就是直径上到端点最大距离最小的点)。
答案就是两棵树的直径的一半(当然这是粗略的说法)加上边权,和两棵树内部的直径长度的最大值。
设直径端点为\(S\)和\(T\),现在想象直径是横过来的一条线,有一堆树挂在上面。
在直径上从左到右枚举删去哪条边,顺带着维护中点在哪里。
有个结论:中点肯定在原来的直径上。
(后面都以\(S\)的一边为例,显然另一边是一样的)
反证法,设中点为\(x\),\(x\)不在直径上。设\(y\)为\(x\)到\(S\)路径上第一个出现在直径上的点。
现在找最远的点\(z\)。
如果\(z\)在\(y\)子树之外,那么路径就是\(x\)到\(y\)和\(y\)到\(z\)的距离。这时候如果要使\(y\)到\(z\)最大,则\(z=S\)。这时候将\(x\)变成\(y\)更优。
如果\(z\)在\(x\)子树之内,那么\(x\)到\(z\)的距离比\(x\)到\(S\)的距离长,与假设矛盾。
如果\(z\)在\(y\)子树之内,在\(x\)子树之外,那么\(y\)到\(z\)的距离比\(y\)到\(S\)的距离长,矛盾。
接下来考虑如何维护直径。
在原来的直径上,对于每个节点,预处理出\(f_x\)表示\(x\)子树中最远点到\(x\)的长度。
设\(disS_x\)为\(x\)到\(S\)的距离。
显然,新的直径的一个端点是\(S\)。直径可以分成在原来直径上和在某棵子树内的两段。
设\(x\)为直径的拐点,则直径的长度为\(disS_x+f_x\)
设\(a\)为直径的中点,则直径一半的长度(形象的说法)为\(max(disS_a,disS_x+f_x-disS_a)\)
现在被删去的边在原来的直径上从左往右移动,每个拐点都能搞出一条路径。在这些路径中找长度最大的,作为直径,然后\(a\)移动到\(max(disS_a,disS_x+f_x-disS_a)\)最小的地方,这时候\(a\)就求出来了。
在这个过程中,我们发现\(a\)只会从\(S\)向\(T\)移动。
所以直接\(O(n)\)做就可以了(题解说要单调队列,但实际上完全不用。具体见代码。)
代码
using namespace std;
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 2000010
#define ll long long
int n;
struct EDGE{
int to,w,num;
EDGE *las;
} e[N*2],*last[N];
int ne;
unsigned long long num;
unsigned long long get(){
num^=(num<<13);
num^=(num>>17);
num^=(num<<5);
return num;
}
void gen(){
int B,D;
scanf("%d%llu%d%d",&n,&num,&B,&D);
for(int i=2;i<=n;i++){
int a=get()%min(i-1,B)+i-min(i-1,B),b=get()%D;
e[ne]={a,b,i-1,last[i]};
last[i]=e+ne++;
e[ne]={i,b,i-1,last[a]};
last[a]=e+ne++;
}
}
ll ans[N];
int q[N];
ll ds[N],dt[N],alen;
int S,T,pre[N],suc[N];
EDGE *et[N];
void init(){
static int vis[N];
int BZ,h,t;
vis[1]=BZ=1;
q[h=t=1]=1;
ll *dis=ds;
dis[1]=0;
while (h<=t){
int x=q[h++],y;
for (EDGE *ei=last[x];ei;ei=ei->las){
y=ei->to;
if (vis[y]!=BZ){
vis[y]=BZ;
dis[y]=dis[x]+ei->w;
q[++t]=y;
}
}
}
S=1;
for (int i=1;i<=n;++i)
if (dis[i]>dis[S])
S=i;
q[h=t=1]=S;
vis[S]=++BZ;
dis[S]=0;
while (h<=t){
int x=q[h++],y;
for (EDGE *ei=last[x];ei;ei=ei->las){
y=ei->to;
if (vis[y]!=BZ){
vis[y]=BZ;
dis[y]=dis[x]+ei->w;
pre[y]=x;
et[y]=ei;
q[++t]=y;
}
}
}
T=S;
for (int i=1;i<=n;++i)
if (dis[i]>dis[T])
T=i;
for (int i=T;i!=S;i=pre[i])
suc[pre[i]]=i;
suc[T]=0;
for (int i=1;i<=n;++i)
if (!suc[i] && i!=T)
pre[i]=0;
}
ll f[N];
int fa[N];
void dp1(int rt){
int h,t;
q[h=t=1]=rt;
fa[rt]=0;
while (h<=t){
int x=q[h++],y;
for (EDGE *ei=last[x];ei;ei=ei->las){
y=ei->to;
if (y!=pre[rt] && y!=suc[rt] && y!=fa[x]){
ans[ei->num]=alen;
fa[y]=x;
q[++t]=y;
}
}
}
for (int i=t;i>=1;--i){
int x=q[i],y;
f[x]=0;
for (EDGE *ei=last[x];ei;ei=ei->las){
y=ei->to;
if (y!=pre[rt] && y!=suc[rt] && y!=fa[x])
f[x]=max(f[x],f[y]+ei->w);
}
}
}
ll gs[N],gt[N];
void dp2(int rt,int *cant,ll *g){
int h,t;
q[h=t=1]=rt;
fa[rt]=0;
while (h<=t){
int x=q[h++],y;
for (EDGE *ei=last[x];ei;ei=ei->las){
y=ei->to;
if (y!=cant[x] && y!=fa[x]){
fa[y]=x;
q[++t]=y;
}
}
}
for (int i=t;i>=1;--i){
int x=q[i],y;
ll fmx=0,smx=0;
f[x]=0;
g[x]=0;
for (EDGE *ei=last[x];ei;ei=ei->las){
y=ei->to;
if (y!=cant[x] && y!=fa[x]){
g[x]=max(g[x],g[y]);
if (f[y]+ei->w>fmx)
smx=fmx,fmx=f[y]+ei->w;
else if (f[y]+ei->w>smx)
smx=f[y]+ei->w;
}
}
f[x]=fmx;
g[x]=max(g[x],fmx+smx);
}
}
ll hs[N],ht[N];
void calc(int beg,int end,int *nxt,ll *h,ll *dis){
int a=beg,mx=beg;
h[beg]=f[beg];
for (int x=nxt[beg];x!=end;x=nxt[x]){
if (dis[x]+f[x]>dis[mx]+f[mx]){
mx=x;
while (a!=x && max(dis[nxt[a]],dis[mx]+f[mx]-dis[nxt[a]])<max(dis[a],dis[mx]+f[mx]-dis[a]))
a=nxt[a];
}
h[x]=max(dis[a],dis[mx]+f[mx]-dis[a]);
}
}
int main(){
freopen("path.in","r",stdin);
freopen("path.out","w",stdout);
gen();
init();
alen=ds[T];
dp2(T,suc,gs),dp2(S,pre,gt);
for (int i=S;i;i=suc[i])
dt[i]=alen-ds[i],dp1(i);
calc(S,T,suc,hs,ds);
calc(T,S,pre,ht,dt);
for (int i=S;i!=T;i=suc[i])
ans[et[suc[i]]->num]=max(max(gs[i],gt[suc[i]]),hs[i]+ht[suc[i]]+et[suc[i]]->w);
ll s=0;
for (int i=1;i<n;++i)
s^=ans[i]%998244353*i%998244353;
printf("%lld\n",s);
return 0;
}
总结
论猜结论的重要性……
6380. 【NOIP2019模拟2019.10.06】小w与最长路(path)的更多相关文章
- 6389. 【NOIP2019模拟2019.10.26】小w学图论
题目描述 题解 之前做过一次 假设图建好了,设g[i]表示i->j(i<j)的个数 那么ans=∏(n-g[i]),因为连出去的必定会构成一个完全图,颜色互不相同 从n~1染色,点i的方案 ...
- 【NOIP2019模拟2019.10.07】果实摘取 (约瑟夫环、Mobius反演、类欧、Stern-Brocot Tree)
Description: 小 D 的家门口有一片果树林,果树上果实成熟了,小 D 想要摘下它们. 为了便于描述问题,我们假设小 D 的家在二维平面上的 (0, 0) 点,所有坐标范围的绝对值不超过 N ...
- 6392. 【NOIP2019模拟2019.10.26】僵尸
题目描述 题解 吼题但题解怎么这么迷 考虑一种和题解不同的做法(理解) 先把僵尸离散化,h相同的钦(ying)点一个大小 (可以发现这样每种情况只会被算正好一次) 计算完全被占领的方案,然后1-方案/ ...
- 6377. 【NOIP2019模拟2019.10.05】幽曲[埋骨于弘川]
题目描述 题解 随便bb 详细题解见 https://www.cnblogs.com/coldchair/p/11624979.html https://blog.csdn.net/alan_cty/ ...
- 6383. 【NOIP2019模拟2019.10.07】果实摘取
题目 题目大意 给你一个由整点组成的矩形,坐标绝对值范围小于等于\(n\),你在\((0,0)\),一开始面向\((1,0)\),每次转到后面第\(k\)个你能看到的点,然后将这条线上的点全部标记删除 ...
- 6374. 【NOIP2019模拟2019.10.04】结界[生与死的境界]
题目 题目大意 给你一个数列,每次可以选择任意两个相邻的数\(x\)和\(y\),将其删去,并在原来位置插入\(x+2y\). 每次询问一个区间,对这个区间进行上述操作.求最后剩下的数最大是多少. 答 ...
- 【NOIP2017模拟6.25】小W的动漫
题目 小W最近迷上了日本动漫,每天都有无数部动漫的更新等着他去看,所以他必须将所有的动漫排个顺序,当然,虽然有无数部动漫,但除了1号动漫,每部动漫都有且仅有一部动漫是它的前传(父亲),也就是说,所有的 ...
- 洛谷P5284 [十二省联考2019]字符串问题(SAM+倍增+最长路)
题面 传送门 题解 首先,我们把串反过来,那么前缀就变成后缀,建一个\(SAM\).我们发现一个节点的后缀是它的所有祖先 那么我们是不是直接按着\(parent\)树建边就可以了呢? 显然不是.我们假 ...
- [JZOJ6359] 【NOIP2019模拟2019.9.15】小ω的树
题目 题目大意 给你一棵树,带点权和边权. 要你选择一个联通子图,使得点权和乘最小边权最大. 支持修改点权操作. 思考历程 显然,最先想到的当然是重构树了-- 重构树就是在做最大生成树的时候,当两个联 ...
随机推荐
- html打开子窗口
第一个参数是打开的链接,第二个参数是窗口的名字,第三个参数是窗口的属性 window.open ("page.html", "newwindow", " ...
- shell 中| 用法
| 运算符 管道符号,是unix一个很强大的功能,符号为一条竖线:"|".用法: command 1 | command 2 他的功能是把第一个命令command 1执行的结果作为 ...
- 关于Linux_监控系统资源/性能命令_vmstat
(系统资源查看命令-vmstat[监控系统资源命令]) command:vmstat [刷新延时 刷新次数] 分解解析: procs:进程信息字段: ...
- Go(二)函数
函数是一等公民 与其他主要编程语言的差异 1.可以有多个返回值 2.所有参数都是值传递 slice.map.channel会有传引用是错觉,如切片背后是数组,是一个数据结构,里面包含了指向对应数组的指 ...
- 用List和Map排序输出
参考:java的treemap反序输出 int->string string->int java对象数组的概述 List import java.io.*; import java.uti ...
- mysql学习-join的使用
sql的执行顺序是从from 开始 join图
- Android中通过进程注入技术修改系统返回的Mac地址
致谢 感谢看雪论坛中的这位大神,分享了这个技术:http://bbs.pediy.com/showthread.php?t=186054,从这篇文章中学习到了很多内容,如果没有这篇好文章,我在研究的过 ...
- Linux 应用程序编程基础
一个计算机应用程序在内存中可以分成两个部分:存放代码的代码段和存放数据的数据段.代码段存放用户编写的代码;数据段存放栈和堆. 相关内存管理函数 #include <stdlib.h> vo ...
- Java BIO socket
package org.rx.socks; import lombok.extern.slf4j.Slf4j; import org.rx.core.LogWriter; import org.rx. ...
- gulp压缩css
gulp压缩css,选用的依赖是gulp-clean-css,在压缩大型项目时还对用到一个dom流压缩文件选取的依赖gulp-dom-src 依赖安装:npm i gulp-clean-css 依赖安 ...