P4775 [NOI2018] 情报中心(线段树合并)

前言

似乎也没有那么难?
但确实也不太好想。

解析

对于两条有交路径 (u1,v1,c1),(u2,v2,c2)(u_1,v_1,c_1),(u_2,v_2,c_2)(u1,v1,c1),(u2,v2,c2),设 t=lca(u1,u1)t=lca(u_1,u_1)t=lca(u1,u1) 为四个 lca 中最深的,那么代价的二倍可以写为 dis(u1,v1)+dis(u2,v2)+dis(u1,u2)+dis(v1,v2)−2c1−2c2dis(u_1,v_1)+dis(u_2,v_2)+dis(u_1,u_2)+dis(v_1,v_2)-2c_1-2c_2dis(u1,v1)+dis(u2,v2)+dis(u1,u2)+dis(v1,v2)2c12c2
枚举 ttt 的位置,距离可以写成 dis(u1,v1)+depu1−2c1+dis(u2,v2)+depu2−2c2+dis(v1,v2)−2deptdis(u_1,v_1)+dep_{u_1}-2c_1+dis(u_2,v_2)+dep_{u_2}-2c_2+dis(v_1,v_2)-2dep_tdis(u1,v1)+depu12c1+dis(u2,v2)+depu22c2+dis(v1,v2)2dept,可以看成 dis(v1,v2)+w1+w2−2deptdis(v_1,v_2)+w_1+w_2-2dep_tdis(v1,v2)+w1+w22dept 的形式。
看到最大距离,容易想到线段树维护直径的经典做法。
可以看成新的“ v1v_1v1” 是原来的点连出一条长度为 w1w_1w1 的边,所以依然可以刻画为树的结构,虽然有负权边,但是由于负权边必然有一个端点是叶子,所以原来的结论还是对的。

每个节点维护子树内“v”节点集合,合并时先更新答案,再线段树合并即可,时空复杂度 O(mlog⁡m+nlog⁡n)O(m\log m+n\log n)O(mlogm+nlogn)

记得要再到达 lca 之前把点删掉。

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define debug(...) fprintf(stderr,__VA_ARGS__)
#define ok debug("line: %d\n",__LINE__)inline ll read(){ll x(0),f(1);char c=getchar();while(!isdigit(c)) {if(c=='-')f=-1;c=getchar();}while(isdigit(c)) {x=(x<<1)+(x<<3)+c-'0';c=getchar();}return x*f;
}
bool mem1;const int N=2e5+100;
const ll inf=2e18;
const int mod=998244353;
const bool Flag=0;#define add(x,y)  ((((x)+=(y))>=mod)&&((x)-=mod))
inline ll ksm(ll x,ll k){ll res(1);while(k){if(k&1) res=res*x%mod;x=x*x%mod;k>>=1;}return res;
}int n,m;struct edge{int to,nxt,w;
}p[N<<1];
int fi[N],cnt;
inline void addline(int x,int y,int w){p[++cnt]=(edge){y,fi[x],w};fi[x]=cnt;
}
int q[N],dep[N],tim,pos[N];
ll dis[N];int pl[N][20];
inline int jump(int x,int anc){if(Flag) printf("jump: x=%d anc=%d\n",x,anc);for(int k=16;k>=0;k--){if(dep[pl[x][k]]<=dep[anc]) continue;x=pl[x][k];}if(Flag) printf("  p=%d\n",x);return x;
}void dfs(int x,int f){dep[x]=dep[f]+1;pos[x]=++tim;q[tim]=x;pl[x][0]=f;for(int k=1;pl[x][k-1];k++) pl[x][k]=pl[pl[x][k-1]][k-1];for(int i=fi[x];~i;i=p[i].nxt){int to=p[i].to;if(to==f) continue;dis[to]=dis[x]+p[i].w;dfs(to,x);q[++tim]=x;}return;
}
int mn[N][20],lg[N],mi[20];
inline int cmp(int x,int y){return dep[x]<dep[y]?x:y;}
void ST(){lg[0]=-1;for(int i=1;i<=tim;i++) lg[i]=lg[i>>1]+1;mi[0]=1;for(int i=1;i<=lg[tim];i++) mi[i]=mi[i-1]<<1;for(int i=1;i<=tim;i++) mn[i][0]=q[i];for(int k=1;k<=lg[tim];k++){for(int i=1;i+mi[k]-1<=tim;i++) mn[i][k]=cmp(mn[i][k-1],mn[i+mi[k-1]][k-1]);}return;
}
inline int Lca(int x,int y){int l=pos[x],r=pos[y];if(l>r) swap(l,r);int k=lg[r-l+1];//printf("    x=%d y=%d  (%d %d) Lca=%d\n",x,y,pos[x],pos[y],cmp(mn[l][k],mn[r-mi[k]+1][k]));return cmp(mn[l][k],mn[r-mi[k]+1][k]);
}
inline ll Dis(int x,int y){return dis[x]+dis[y]-2*dis[Lca(x,y)];
}
struct pt{int id;ll w;
};
inline ll calc(const pt &a,const pt &b){  return Dis(a.id,b.id)+a.w+b.w;
}
int id[N],ed[N],rku[N],rkv[N];struct node{pt x,y;
};
inline void print(const node &a,int op=1){printf("[ (%d %lld) (%d %lld) ] %c",a.x.id,a.x.w,a.y.id,a.y.w,op?'\n':' ');
}
inline ll getans(const node &a,const node &b){ll q=calc(a.x,b.x),w=calc(a.x,b.y),e=calc(a.y,b.x),r=calc(a.y,b.y),mx=max({q,w,e,r});return mx;
}
inline node merge(const node &a,const node &b){ll q=calc(a.x,b.x),w=calc(a.x,b.y),e=calc(a.y,b.x),r=calc(a.y,b.y),t=calc(a.x,a.y),y=calc(b.x,b.y),mx=max({q,w,e,r,t,y});if(mx==q) return (node){a.x,b.x};if(mx==w) return (node){a.x,b.y};if(mx==e) return (node){a.y,b.x};if(mx==r) return (node){a.y,b.y};if(mx==t) return (node){a.x,a.y};if(mx==y) return (node){b.x,b.y};assert(0);
}struct tree{int ls,rs;node o;
}tr[N*30];
int rt[N],tot;
inline void pushup(int k){tr[k].o=merge(tr[tr[k].ls].o,tr[tr[k].rs].o);/*printf("merge: ");print(tr[tr[k].ls].o,0);print(tr[tr[k].rs].o,0);print(tr[k].o,1);*/return;
}
#define mid ((l+r)>>1)
inline int New(){tr[++tot]=tr[0];return tot;
}
void upd(int &k,int l,int r,int p,ll w,int op){if(!k) k=New();if(l==r){assert(id[l]);if(op==1) tr[k].o.x=(pt){id[l],w};else tr[k].o.x=(pt){id[l],-inf};return;}if(p<=mid) upd(tr[k].ls,l,mid,p,w,op);else upd(tr[k].rs,mid+1,r,p,w,op);pushup(k);return;
}
int merge(int x,int y){if(!x||!y) return x|y;int now=++tot;tr[now].ls=merge(tr[x].ls,tr[y].ls);tr[now].rs=merge(tr[x].rs,tr[y].rs);pushup(now);return now;
}struct ope{int op,p;ll w;
};
vector<ope>ve[N];int u[N],v[N];
ll c[N];
int S;
ll ans;void solve(int x,int f){for(int i=fi[x];~i;i=p[i].nxt){int to=p[i].to;if(to==f) continue;solve(to,x);}if(Flag) printf("solve: x=%d\n",x);for(ope o:ve[x]){    if(o.op==1){pt ww=(pt){id[o.p],o.w};ans=max(ans,calc(ww,tr[rt[x]].o.x)-2*dis[x]);ans=max(ans,calc(ww,tr[rt[x]].o.y)-2*dis[x]);upd(rt[x],1,S,o.p,o.w,o.op);if(Flag) printf("  ins: p=%d x=%d\n",o.p,id[o.p]);      }}for(int i=fi[x];~i;i=p[i].nxt){int to=p[i].to;if(to==f) continue;ll o=getans(tr[rt[x]].o,tr[rt[to]].o)-2*dis[x];if(Flag) if(o>ans){printf("%d -> %d o=%lld ",x,to,o);print(tr[rt[x]].o,0);print(tr[rt[to]].o,1);}ans=max(ans,o);rt[x]=merge(rt[x],rt[to]);}for(ope o:ve[x]){    if(o.op==-1){upd(rt[x],1,S,o.p,o.w,o.op);if(Flag) printf("  del: p=%d x=%d\n",o.p,id[o.p]);}}return;
}void init(){tim=0;cnt=-1;tot=0;ans=-inf;tr[0].o.x=tr[0].o.y=(pt){1,-inf};for(int i=1;i<=n;i++){fi[i]=-1;memset(pl[i],0,sizeof(pl[i]));ed[i]=0;rt[i]=0;ve[i].clear();}
}void work(){n=read();init();for(int i=1;i<n;i++){int x=read(),y=read(),w=read();addline(x,y,w);addline(y,x,w);}dfs(1,0);ST();m=read();for(int i=1;i<=m;i++){u[i]=read();v[i]=read();c[i]=Dis(u[i],v[i])-read()*2;rku[i]=++ed[u[i]];rkv[i]=++ed[v[i]];}for(int i=1;i<=n;i++){ed[i]+=ed[i-1];for(int j=ed[i-1]+1;j<=ed[i];j++) id[j]=i;}S=ed[n];for(int i=1;i<=m;i++){int anc=Lca(u[i],v[i]);if(anc!=u[i]){int p=jump(u[i],anc);ve[u[i]].push_back((ope){1,ed[v[i]-1]+rkv[i],c[i]+dis[u[i]]});ve[p].push_back((ope){-1,ed[v[i]-1]+rkv[i],c[i]+dis[u[i]]});}if(anc!=v[i]){int p=jump(v[i],anc);ve[v[i]].push_back((ope){1,ed[u[i]-1]+rku[i],c[i]+dis[v[i]]});ve[p].push_back((ope){-1,ed[u[i]-1]+rku[i],c[i]+dis[v[i]]});}}solve(1,0);if(ans<-1e18) puts("F");else printf("%lld\n",ans>>1);
}bool mem2;
signed main(){#ifndef ONLINE_JUDGEfreopen("a.in","r",stdin);freopen("a.out","w",stdout);#endifdebug("mem=%.2lf\n",abs(&mem2-&mem1)/1024./1024);int T=read();while(T--){//if(T%100==0) debug("%d\n",T);work();}return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/316645.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[骗分技巧——随机化Ⅱ] [Poi2014]Couriers,CodeChef - TKCONVEX

文章目录[Poi2014]CouriersproblemsolutioncodeCodeChef - TKCONVEXproblemsolutioncode随机算法的典型套路&#xff1a;枚举太花时&#xff0c;转化为随机一个数。然后通过对正确率的分析&#xff0c;选择一个随机的次数来卡。前提是要保证每一次检验随机是否为答案的时间复杂…

[NewLife.XCode]功能设置

NewLife.XCode是一个有10多年历史的开源数据中间件&#xff0c;由新生命团队(2002~2019)开发完成并维护至今&#xff0c;以下简称XCode。整个系列教程会大量结合示例代码和运行日志来进行深入分析&#xff0c;蕴含多年开发经验于其中&#xff0c;代表作有百亿级大数据实时计算项…

I love max and multiply HDU - 6971(详细解答)

I love max and multiply HDU - 6971 题意&#xff1a; 数组a和b&#xff0c;现在构造一个数组c&#xff0c;使得c[k]max(a[i] * b[j]) , i&j>k 求数组c的和 题解&#xff1a; 我们可以考虑求出所有Dkmax(Ai * Bj)并满足i&jk&#xff0c;然后再从后向前取&#…

[NewLife.XCode]数据模型文件

NewLife.XCode是一个有10多年历史的开源数据中间件&#xff0c;由新生命团队(2002~2019)开发完成并维护至今&#xff0c;以下简称XCode。整个系列教程会大量结合示例代码和运行日志来进行深入分析&#xff0c;蕴含多年开发经验于其中。开源地址&#xff1a;https://github.com/…

[HNOI2013]数列(差分)

[HNOI2013]数列 problem 洛谷链接 solution 假设每天的股价为 a[i]a[i]a[i]。则需满足 ∀i<ka[i1]−a[i]≤m\forall_{i<k}a[i1]-a[i]\le m∀i<k​a[i1]−a[i]≤m。又有参数满足 m(k−1)<nm(k-1)<nm(k−1)<n。 也就是说每天的股价都可以取到上限&#xf…

24dian(牛客多校第三场)

24dian(牛客多校第三场) 题意&#xff1a; 给你n张牌&#xff0c;每张牌的大小为1 ~ 13&#xff0c;问这些牌与加减乘除任意组合(可以使用括号)&#xff0c;且但所有的有效解在计算过程中都涉及到分数&#xff0c;即非整数&#xff0c;能否组成答案m&#xff0c;如果可以&…

[NewLife.XCode]高级增删改

NewLife.XCode是一个有10多年历史的开源数据中间件&#xff0c;支持nfx/netstandard&#xff0c;由新生命团队(2002~2019)开发完成并维护至今&#xff0c;以下简称XCode。整个系列教程会大量结合示例代码和运行日志来进行深入分析&#xff0c;蕴含多年开发经验于其中&#xff0…

[AtCoder Grand Contest 048] D - Pocky Game(区间dp + 博弈)

problem AtCoder solution 注意&#xff1a;本题不是平等博弈&#xff0c;因为先手只能取最左边&#xff0c;后手只能取最右边。 设 f[l][r][k]:f[l][r][k]:f[l][r][k]: 只剩下区间 [l,r][l,r][l,r] 等待操作&#xff0c;第 lll 堆石子数量为 kkk 的时候&#xff0c;先手是…

P4147 玉蟾宫

P4147 玉蟾宫 题意&#xff1a; 给你一个n * m的矩阵&#xff0c;矩阵每个值有F或R&#xff0c;求最大的全为F的矩阵&#xff0c;输出面积 * 3 题解&#xff1a; 很明显&#xff0c;求最大01矩阵&#xff0c;悬线法或者单调栈 对于模板除了要记熟还要知道原理&#xff0c;不…

[NewLife.XCode]数据初始化

NewLife.XCode是一个有10多年历史的开源数据中间件&#xff0c;支持nfx/netstandard&#xff0c;由新生命团队(2002~2019)开发完成并维护至今&#xff0c;以下简称XCode。整个系列教程会大量结合示例代码和运行日志来进行深入分析&#xff0c;蕴含多年开发经验于其中&#xff0…

I love counting HDU - 6964

I love counting HDU - 6964 题意&#xff1a; 一个数组c&#xff0c;给你了(l,r)一个范围&#xff0c;问这个范围内满足ci ^ a < b数量的有多少&#xff1f; 题解&#xff1a; 我第一反应是莫队&#xff0c;直接莫队得到结果&#xff0c;但是发现样例不对&#xff0c;再…

CF98E Help Shrek and Donkey(纳什博弈 + 大讨论)

problem 洛谷链接 solution 纳什均衡 是博弈论中一种解的概念&#xff0c;它是指满足下面性质的策略组合&#xff1a;任何一位玩家在此策略组合下单方面改变自己的策略&#xff0c;其他玩家策略不变&#xff0c;都不会提高自身的收益。 一个策略组合被称为纳什均衡当且仅当…

[NewLife.XCode]反向工程(自动建表建库大杀器)

NewLife.XCode是一个有10多年历史的开源数据中间件&#xff0c;支持nfx/netstandard&#xff0c;由新生命团队(2002~2019)开发完成并维护至今&#xff0c;以下简称XCode。整个系列教程会大量结合示例代码和运行日志来进行深入分析&#xff0c;蕴含多年开发经验于其中&#xff0…

树上启发式合并

文章内容选自OI Wiki 参考博客 内容&#xff1a; 树上启发式合并&#xff08;dsu on tree&#xff09;对于某些树上离线问题可以速度大于等于大部分算法且更易于理解和实现的算法。 他是用来解决一类树上询问问题&#xff0c;一般这种问题有两个特征&#xff1a; 只有对子树…

CF1270H Number of Components(线段树)

problem 洛谷链接 solution 定理 若 i<ji<ji<j 且 i,ji,ji,j 联通&#xff0c;则必有 k∈(i,j)k\in(i,j)k∈(i,j) 也与 i,ji,ji,j 联通。 下面给出证明&#xff0c;挺显然的。 若 ai<aja_i<a_jai​<aj​&#xff0c;则一定有 ai<ak∨ak<aja_i<…

tex模板

\documentclass{beamer} \usetheme{Madrid} \usecolortheme{default} \usepackage{ctex} \usefonttheme[math]{serif}\usepackage{graphicx} \graphicspath{{img/},{pics/}} % 图片在img目录\title{} \author{} \institute{} \date{\today} \begin{document}\maketitle\begin{f…

Wexflow:C#中的开源工作流引擎

Wexflow是一个高性能、可扩展、模块化和跨平台的工作流引擎。Wexflow在GitHub&#xff1a;https://github.com/aelassas/Wexflow。Wexflow的目标是在没有用户干预的情况下自动执行重复任务。在Wexflow的帮助下&#xff0c;构建自动化和工作流过程变得简单。Wexflow还有助于使长…

分析数学笔记

文章目录夹逼收敛定理(P45):单调收敛定理(P50):闭区间套定理(P56)&#xff1a;有限覆盖定理(P59)&#xff1a;可数集(P62)&#xff1a;聚点(P62)&#xff1a;聚点原理(P62)&#xff1a;波尔查诺-魏尔斯特拉斯定理(P64)柯西序列&柯西收敛准则(P65)压缩映照原理(P67)上下极限…

ASP.NET Core 沉思录 - Logging 的两种介入方法

ASP.NET Core 中依赖注入是一个很重要的环节。因为几乎所有的对象都是由它创建的&#xff08;相关文章请参见《ASP.NET Core 沉思录 - ServiceProvider 的二度出生》&#xff09;。因此整个日志记录的相关类型也被直接添加到了 IServiceCollection 中。今天我们将介绍各个接口/…

CF936D World of Tank(思维dp)

problem 洛谷链接 solution 有一种 dpdpdp 并不常见。其主要思想大概就是积累后再支出 / 先预支后再填充。 本题就是积累后再支出。显然炮冷却好了后就一直处于可用状态&#xff0c;玩没玩过游戏的都知道一冷却好就打一定不会劣于等一会再打&#xff0c;因为这道题的炮也没…