Loj #6073.「2017 山东一轮集训 Day5」距离
Loj #6073.「2017 山东一轮集训 Day5」距离
Description
给定一棵 \(n\) 个点的边带权的树,以及一个排列$ p\(,有\)q $个询问,给定点 \(u, v, k\),设$ path(u,v) \(表示\) u$ 到 $v \(的路径,\)dist(u,v) \(表示\) u$ 到\(v\) 的距离,希望你求出

Input
第一行一个整数 \(type =0/1\)表示这个测试点的数据类型。
第二行两个整数 \(n,q\)。
接下来$ n−1$ 行,每行三个整数 \(ui,vi,ci,\)代表树上有一条连接$ ui,vi$ 的权值为$ci $的边。
接下来一行 \(n\) 个正整数表示给定的排列 p。
接下来 \(q\) 行,每行三个整数 \(u′,v′,k′\),记lastAns 为上一次询问的答案,假如这是第一次则\(lastAns=0\),那么这个询问对应的\(u,v,k\) 满足:

思路还是比较妙啊。
题目的难点在于求一个点与一个点集的\(lca\)深度之和。我们可以将点集中的每个点到根的路径上的标记都\(+1\)。询问点\(k\)到这个点集的\(lca\)深度和的时候我们就可以询问该点到根路径上的所有边权与标记的乘积之和。
由于是询问\((a,b)\)路径上的信息,我们就用主席树维护,询问的时候做差分。对于一个节点\(a\),它的信息由\(fa_a\)继承下来,再加上\(p_a\)的信息就好了。
考试时不会,写的虚树,常数大到自闭。
[HNOI2015]开店 的主席树做法也是基于这个原理的。
代码:
#include<bits/stdc++.h>
#define ll long long
#define N 200005
using namespace std;
inline ll Get() {ll x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}while('0'<=ch&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}return x*f;}
int n,m,type;
int p[N];
ll pre[N];
ll ans;
struct road {
int to,next;
ll d;
}s[N<<1];
int h[N],cnt;
void add(int i,int j,ll d) {s[++cnt]=(road) {j,h[i],d};h[i]=cnt;}
ll sum_dis[N];
int size[N],son[N];
int fa[N],top[N],dep[N];
ll dis[N];
void dfs(int v) {
size[v]=1;
for(int i=h[v];i;i=s[i].next) {
int to=s[i].to;
if(to==fa[v]) continue ;
dep[to]=dep[v]+1;
dis[to]=dis[v]+s[i].d;
fa[to]=v;
dfs(to);
size[v]+=size[to];
if(size[son[v]]<size[to]) son[v]=to;
}
}
int dfn[N],id;
void dfs2(int v,int tp) {
sum_dis[v]=sum_dis[fa[v]]+dis[p[v]];
dfn[v]=++id;
pre[dfn[v]]=dis[v]-dis[fa[v]];
top[v]=tp;
if(son[v]) dfs2(son[v],tp);
for(int i=h[v];i;i=s[i].next) {
int to=s[i].to;
if(to==fa[v]||to==son[v]) continue ;
dfs2(to,to);
}
}
int lca(int a,int b) {
while(top[a]!=top[b]) {
if(dep[top[a]]<dep[top[b]]) swap(a,b);
a=fa[top[a]];
}
return dep[a]<dep[b]?a:b;
}
int tot;
int rt[N];
int lx,rx;
struct tree {
int ls,rs;
ll tag,sum;
}tr[N*150];
void Modify(int &v,int old,int lx,int rx,int l,int r,ll f) {
if(lx>r||rx<l) return ;
v=++tot;
tr[v]=tr[old];
if(l<=lx&&rx<=r) {
tr[v].tag+=f;
return ;
}
int L=max(lx,l),R=min(rx,r);
tr[v].sum+=f*(pre[R]-pre[L-1]);
int mid=lx+rx>>1;
Modify(tr[v].ls,tr[old].ls,lx,mid,l,r,f);
Modify(tr[v].rs,tr[old].rs,mid+1,rx,l,r,f);
}
void Modify(int v) {
int a=p[v];
while(top[a]!=top[1]) {
Modify(rt[v],rt[v],lx,rx,dfn[top[a]],dfn[a],1);
a=fa[top[a]];
}
Modify(rt[v],rt[v],lx,rx,dfn[1],dfn[a],1);
}
ll query(int v,int lx,int rx,int l,int r) {
if(!v||lx>r||rx<l) return 0;
if(l<=lx&&rx<=r) return tr[v].sum+tr[v].tag*(pre[rx]-pre[lx-1]);
ll ans=tr[v].tag*(pre[min(r,rx)]-pre[max(l,lx)-1]);
int mid=lx+rx>>1;
ans+=query(tr[v].ls,lx,mid,l,r)+query(tr[v].rs,mid+1,rx,l,r);
return ans;
}
ll query(int rt,int a) {
ll ans=0;
while(top[a]!=top[1]) {
ans+=query(rt,lx,rx,dfn[top[a]],dfn[a]);
a=fa[top[a]];
}
ans+=query(rt,lx,rx,dfn[1],dfn[a]);
return ans;
}
void dfs3(int v) {
rt[v]=rt[fa[v]];
Modify(v);
for(int i=h[v];i;i=s[i].next) {
int to=s[i].to;
if(to==fa[v]) continue ;
dfs3(to);
}
}
int main() {
type=Get();
n=Get(),m=Get();
int a,b,d;
for(int i=1;i<n;i++) {
a=Get(),b=Get(),d=Get();
add(a,b,d),add(b,a,d);
}
for(int i=1;i<=n;i++) p[i]=Get();
lx=1,rx=n;
dfs(1);
dfs2(1,1);
for(int i=1;i<=n;i++) pre[i]+=pre[i-1];
dfs3(1);
while(m--) {
ll x=Get()^(ans*type),y=Get()^(ans*type),k=Get()^(ans*type);
int f=lca(x,y);
ans=sum_dis[x]+sum_dis[y]-sum_dis[f]-sum_dis[fa[f]];
ans+=(dep[x]+dep[y]-2*dep[f]+1)*dis[k];
ans-=2*(query(rt[x],k)+query(rt[y],k)-query(rt[f],k)-query(rt[fa[f]],k));
cout<<ans<<"\n";
}
return 0;
}
Loj #6073.「2017 山东一轮集训 Day5」距离的更多相关文章
- loj#6073. 「2017 山东一轮集训 Day5」距离(树链剖分 主席树)
题意 题目链接 Sol 首先对询问差分一下,我们就只需要统计\(u, v, lca(u, v), fa[lca(u, v)]\)到根的路径的贡献. 再把每个点与\(k\)的lca的距离差分一下,则只需 ...
- loj#6073. 「2017 山东一轮集训 Day5」距离(费用流)
题意 题目链接 Sol 我们可以把图行列拆开,同时对于行/列拆成很多个联通块,然后考虑每个点所在的行联通块/列联通块的贡献. 可以这样建边 从S向每个行联通块连联通块大小条边,每条边的容量为1,费用为 ...
- 「2017 山东一轮集训 Day5」距离
/* 写完开店再写这个题目顿时神清气爽, 腰也不疼了, 眼也不花了 首先考虑将询问拆开, 就是查询一些到根的链和点k的关系 根据我们开店的结论, 一个点集到一个定点的距离和可以分三部分算 那么就很简单 ...
- Loj #6069. 「2017 山东一轮集训 Day4」塔
Loj #6069. 「2017 山东一轮集训 Day4」塔 题目描述 现在有一条 $ [1, l] $ 的数轴,要在上面造 $ n $ 座塔,每座塔的坐标要两两不同,且为整点. 塔有编号,且每座塔都 ...
- Loj 6068. 「2017 山东一轮集训 Day4」棋盘
Loj 6068. 「2017 山东一轮集训 Day4」棋盘 题目描述 给定一个 $ n \times n $ 的棋盘,棋盘上每个位置要么为空要么为障碍.定义棋盘上两个位置 $ (x, y),(u, ...
- 「2017 山东一轮集训 Day5」苹果树
「2017 山东一轮集训 Day5」苹果树 \(n\leq 40\) 折半搜索+矩阵树定理. 没有想到折半搜索. 首先我们先枚举\(k\)个好点,我们让它们一定没有用的.要满足这个条件就要使它只能和坏 ...
- LOJ #6074. 「2017 山东一轮集训 Day6」子序列
#6074. 「2017 山东一轮集训 Day6」子序列 链接 分析: 首先设f[i][j]为到第i个点,结尾字符是j的方案数,这个j一定是从i往前走,第一个出现的j,因为这个j可以代替掉前面所有j. ...
- loj #6077. 「2017 山东一轮集训 Day7」逆序对
#6077. 「2017 山东一轮集训 Day7」逆序对 题目描述 给定 n,k n, kn,k,请求出长度为 n nn 的逆序对数恰好为 k kk 的排列的个数.答案对 109+7 10 ^ 9 ...
- LOJ #6119. 「2017 山东二轮集训 Day7」国王
Description 在某个神奇的大陆上,有一个国家,这片大陆的所有城市间的道路网可以看做是一棵树,每个城市要么是工业城市,要么是农业城市,这个国家的人认为一条路径是 exciting 的,当且仅当 ...
随机推荐
- tomcat开启自启动
linux方式 #!/bin/bash #chkconfig: #description: Starts and Stops the Tomcat daemon. #by benjamin ##### ...
- Echarts3.0 引入百度地图(转载)
转载来源: https://blog.csdn.net/yc_1993/article/details/52431989 Echarts3.0引入百度地图 update: 由于目前echarts3.8 ...
- mybatis_08 mybatis与hibernate的区别
这个问题常常被面试官当做面试题 mybatis与hibernate喜忧参半,各有特点 Mybatis技术特点: 好处: 1. 通过直接编写SQL语句,可以直接对SQL进行性能的优化: 2. 学习门 ...
- spring aop 实践
之前用的ssm框架,大部分只是利用spring的IOC特性,很明显这能够为我们开发人员在对象的创建上面节省大部分时间.当相似得到业务越来越多,很多代码也是越来越重复,轮子是越来越重复,比如验证用户登录 ...
- linux下允许和禁止root远程登录的方法
1.vi /etc/ssh/sshd_config,将PermitRootLogin的值改成yes,并保存 PermitRootLogin yes 另外需要添加 AllowUsers root SA ...
- mapper代理开发步骤
1:先写Mapper接口,UserMapper.java 2:然后遵循4条开发规范,写映射文件,UserMapper.xml 3:将映射文件,UserMapper.xml加入到SqlMapConfig ...
- struts配置文件说明
(1)DOCTYPE(文档类型),所有的struts配置文件都需要有正确的doctype. (2)<struts>是根标记元素,在其下使用<package>标签声明不同的包. ...
- 如何制作微信动态表情包 GIF制作工具哪个好
表情包已经成为我们生活聊天中必不可少的一部分,但是如何制作微信动态表情包呢?自己制作的表情包更加独有个性,今天小编带大家看一波原创表情包的制作方法吧! 使用工具:电脑 操作方法: 1.首先在手机上也是 ...
- JVM调优(二)经验参数设置
调优设置具体解析 堆大小设置 JVM 中最大堆大小有三方面限制:相关操作系统的数据模型(32-bt还是64-bit)限制:系统的可用虚拟内存限制:系统的可用物理内存限制.32位系统下,一般限制在1.5 ...
- Android为TV端助力 deep link(深度链接)与自定义协议!
此自定义仅供参考! 首先打开androidManifest.xml 在MainActivity中添加如下内容: <activity android:name=".MainActivit ...