首页 > 其他分享 >P4069 题解

P4069 题解

时间:2023-11-08 22:35:38浏览次数:39  
标签:node int 题解 线段 tree P4069 now dis

简要题意

给定一棵 \(n\) 个点的树,树有边权。

对每个点维护一个集合 \(S_u\),一开始集合均包含整数 \(123456789123456789\)。

设 \({\rm dis}_{a,b}\) 为树上两点 \(a\),\(b\) 的距离。

共 \(m\) 次操作,分为如下两种:

  • s t a b: 设 \(f\) 为 \(s\),\(t\) 路径上的点集,对与 \(\forall t\in f\),给 \(t\) 所对应的集合里加入 \(a\times {\rm dis}_{s,t} + b\)。
  • s t: 设 \(f\) 为 \(s\),\(t\) 路径上的点集,求 \(\min\{\bigcup_{x\in f} S_x\}\) 的值。

其中 \(1\le n\le 10^5\)。

前置知识

  1. 树链剖分
  2. 李超线段树

解题方法

首先看到 \(a\times dis+b\),是一个一次函数的形式,不妨考虑先树剖一下,然后用永久化标记的李超线段树维护最大值。

横坐标自然是取个确定的距离标准。取每个点到根节点的距离 \(dis[i]\) 作为 \(i\) 的横坐标好了,这样对于同一条重链,横坐标还是递增的。

对于每次插入操作,先求出 \(s\) 和 \(t\) 的 \(lca\),预处理出每个点到根节点的距离 \(dis[u]\),然后化简一下式子。

  1. 对于 \(s\) 到 \(lca\) 的那条路径上的点 \(u\),增加的贡献是

\[a\times (dis[s]-dis[u])+b=-a\times dis[u] + a\times dis[s] +b \]

  1. 对于 \(t\) 到 \(lca\) 的那条路径上的点,增加的贡献是

\[a\times (dis[s]+dis[u]-2\times dis[lca])+b=a\times dis[u] + a\times (dis[s]-2\times dis[lca]) +b \]

然后就可以插入了。

现在问题就剩如果维护区间最小值,容易发现对于一个区间内的线段,最小值无非就是从两个端点的地方取到,所以线段树上再维护一个区间最小值,每次向上传递,最后区间查询的时候,经过的区间上存的优势线段也能为答案作出贡献,算上就好了。重点在于怎样合并两条线段,具体可以分为以下三种情况:

  1. 如果新线段在当前节点的定义域中完全小于原来的线段。应舍去原来的线段,并用当前线段的两个端点更新最小值。

  2. 新线段在当前节点的定义域中完全大于原来的线段,应舍去这条新线段。

  3. 新加入的线段和原来的线段在当前的定义域中有交点。求一下两条线段的交点横坐标 \(x\)。如果新线段的左端点大于旧线段的左端点,或 \(x\le mid\),就往左下放;如果新线段的右端点小于旧线段的右交点,或 \(x>mid\),就往右下放。

李超树维护线段是 \(O(\log^2n)\) 的,再加上树剖跳链的复杂度,总的时间复杂度是 \(O(n\log^3n)\),应该是可以过的吧……

#include <iostream>
#define MAXN 100005
using namespace std;
const long long INF = 123456789123456789;
int n, m, u, v, w, op, s, t, tmp, tp;
struct edge{int w, to, nxt;}e[MAXN << 1];
int head[MAXN], cnt = 1;
int fa[MAXN], dep[MAXN], siz[MAXN], son[MAXN];
int dfn[MAXN], vis[MAXN], rnk[MAXN], tot;
long long dis[MAXN], k[MAXN << 1], b[MAXN << 1];
struct seg{
	int ls, rs, tag;
	long long minn;
}tree[MAXN << 2];
int read(){
	int t = 1, x = 0;char ch = getchar();
	while(!isdigit(ch)){if(ch == '-')t = -1;ch = getchar();}
	while(isdigit(ch)){x = (x << 1)+ (x << 3)+ (ch ^ 48);ch = getchar();}
	return x * t;
}
void write(long long x){
	if(x < 0){putchar('-');x = -x;}
	if(x >= 10)write(x / 10);
	putchar(x % 10 ^ 48);
}
void add(int u, int v, int w){
	cnt++;e[cnt].w = w;e[cnt].to = v;e[cnt].nxt = head[u];head[u] = cnt;
	cnt++;e[cnt].w = w;e[cnt].to = u;e[cnt].nxt = head[v];head[v] = cnt;
}
long long calc(int id, int x){
	return k[id] * dis[rnk[x]] + b[id];
}
void dfs1(int now, int fat, int deep){
    dep[now] = deep;siz[now] = 1;fa[now] = fat;int maxson = -1;
    for(int i = head[now] ; i != 0 ; i = e[i].nxt){
        int v = e[i].to, w = e[i].w;
        if(v != fat){
            dis[v] = dis[now] + w;
			dfs1(v, now, deep + 1);siz[now] += siz[v];
            if(siz[v] > maxson){
                maxson = siz[v];son[now] = v;
            }
        }
    }
}
void dfs2(int now, int fat, int top){
    tot++;dfn[now] = tot;rnk[tot] = now;vis[now] = top;
    if(son[now] != 0){
        dfs2(son[now], now, top);
        for(int i = head[now] ; i != 0 ; i = e[i].nxt){
            int v = e[i].to;
            if(v != fat && v != son[now])dfs2(v, now, v);
        }
    }
}
int lca(int u, int v){
    while(vis[u] != vis[v]){
        if(dep[vis[u]] < dep[vis[v]])swap(u, v);
        u = fa[vis[u]];
    }
    return dep[u] < dep[v] ? u : v;
}
void pushup(int node){
    if(tree[node].ls == tree[node].rs)
        tree[node].minn = min(calc(tree[node].tag, tree[node].ls), 
	  						  calc(tree[node].tag, tree[node].rs));
    else tree[node].minn = min(min(tree[node << 1].minn, 
	                               tree[node << 1 | 1].minn), 
							   min(calc(tree[node].tag, tree[node].ls), 
							   	   calc(tree[node].tag, tree[node].rs)));
}
void build(int node, int left, int right){
    tree[node].ls = left;
	tree[node].rs = right;
	tree[node].minn = INF;
    if(left != right){
		int mid = (left + right) >> 1;
		build(node << 1, left, mid);
		build(node << 1 | 1, mid + 1, right);
	}
}
void change(int node, int x){
    int &y = tree[node].tag;
	int mid = (tree[node].ls + tree[node].rs) >> 1;
    if(calc(x, mid) < calc(y, mid))swap(x, y);
    if(calc(x, tree[node].ls) < calc(y, tree[node].ls))change(node << 1, x);
    if(calc(x, tree[node].rs) < calc(y, tree[node].rs))change(node << 1 | 1, x);
}
void update(int node, int left, int right, int x){
    if(left <= tree[node].ls && tree[node].rs <= right)return change(node, x), pushup(node), void();
    int mid = (tree[node].ls + tree[node].rs) >> 1;
    if(left <= mid)update(node << 1, left, right, x);
    if(right > mid)update(node << 1 | 1, left, right, x);
    pushup(node);
}
long long query(int node, int left, int right){
    if(left <= tree[node].ls && tree[node].rs <= right)return tree[node].minn;
    int mid = (tree[node].ls + tree[node].rs) >> 1;
    long long res = min(calc(tree[node].tag, max(left, tree[node].ls)), 
						calc(tree[node].tag, min(right, tree[node].rs)));
    if(left <= mid)res = min(res, query(node << 1, left, right));
    if(right > mid)res = min(res, query(node << 1 | 1, left, right));
    return res;
}
void updtree(int u, int v, int x){
    while (vis[u] != vis[v]){
        if(dep[vis[u]] < dep[vis[v]])swap(u, v);
        update(1, dfn[vis[u]], dfn[u], x);
        u = fa[vis[u]];
    }
    if(dep[u] > dep[v])swap(u, v);
    update(1, dfn[u], dfn[v], x);
}
long long quetree(int u, int v){
    long long res = INF;
    while (vis[u] != vis[v]){
        if(dep[vis[u]] < dep[vis[v]])swap(u, v);
        res = min(res, query(1, dfn[vis[u]], dfn[u]));
        u = fa[vis[u]];
    }
    if(dep[u] > dep[v])swap(u, v);
    res = min(res, query(1, dfn[u], dfn[v]));
    return res;
}
int main(){
    n = read();m = read();
	for(int i = 1 ; i < n ; i ++)
		u = read(),v = read(),w = read(),add(u, v, w);
    dfs1(1, 0, 0);dfs2(1, 0, 1);b[0] = INF;build(1, 1, n);
    while(m--){
        op = read();
        if(op == 1){
            u = read();v = read();s = read();t = read();tmp = lca(u, v);
            tp++;k[tp] = -s;b[tp] = t + 1LL * dis[u] * s;updtree(u, tmp, tp);
            tp++;k[tp] = s;b[tp] = t + 1LL * dis[u] * s - 2LL * dis[tmp] * s;updtree(tmp, v, tp);
        }else cout << quetree(read(), read()) << endl;
    }
    return 0;
}

标签:node,int,题解,线段,tree,P4069,now,dis
From: https://www.cnblogs.com/tsqtsqtsq/p/17818497.html

相关文章

  • 上序问题解决补充(1)
    我发现好像只在idea里面整插件是不可以的你还需要下一个wampSERVER然后吧!他这个东西需要在法国官网下载,很他娘的慢,显示下载时间需要一天想不到吧我找到了中文站Wampserver3.3.064位官方版下载-WampServer中文站噔噔噔噔,闪亮登场......
  • cf908(div2)题解(补题)
    纪念这次div2让我上绿名,但还是有点遗憾,差一点就可以过三题超神了比赛链接cf908div2A这题是个骗人题,整个比赛会停下来就是一个人赢够了回合数,那么在谁这停下来就是谁赢了整个比赛,不用管每回合赢得规则。#include<iostream>usingnamespacestd;#include<string>intmain(){......
  • Qt - QWidget::setGeometry()不生效问题解决方案
    开发过程中经常碰到setGeometry()不生效的问题,发现只要在setGeometry()之前调用一下show()或者setVisible(true)就可以了!问题就出在setVisible(true)!!!setVisible()会判断当前控件的WA_WState_Created属性,意思就是看看控件是否已经创建了window,如果为没有创建,就调用create()方......
  • 第三方组件及计算属性传参的问题解决方式
    1.前言唉,好想玩滋嘣。2.计算属性直接传参接收不到表格数据某一列需要用的计算属性时,模板中使用计算属性fullName就会直接调用fullName函数,而在模板中fullName(item)相当于fullName()(item),此处为函数柯里化。<el-table-columnlabel="名称"align="center"min-width=......
  • Balance Addicts 题解
    BalanceAddicts题目大意给定序列\(a\),求有多少种合法的划分方案。定义一种划分方案是合法的当且仅当划分出的各段序列的和构成回文序列。思路分析一种不太一样的做法。我们先对\(a\)做一遍前缀和,得到\(s\)。观察各段序列的和形式:\[s_{p_1},s_{p_2}-s_{p_1},s_{p_3}......
  • P2146 [NOI2015] 软件包管理器 题解
    [NOI2015]软件包管理器题目背景Linux用户和OSX用户一定对软件包管理器不会陌生。通过软件包管理器,你可以通过一行命令安装某一个软件包,然后软件包管理器会帮助你从软件源下载软件包,同时自动解决所有的依赖(即下载安装这个软件包的安装所依赖的其它软件包),完成所有的配置。Debi......
  • 【洛谷 P4414】[COCI2006-2007#2] ABC 题解(排序)
    [COCI2006-2007#2]ABC题面翻译【题目描述】三个整数分别为。这三个数字不会按照这样的顺序给你,但它们始终满足条件:。为了看起来更加简洁明了,我们希望你可以按照给定的顺序重新排列它们。【输入格式】第一行包含三个正整数,不一定是按这个顺序。这三个数字都小于或等于。第二行包......
  • 前端计算数字精度丢失问题解决方法记录 | 京东云技术团队
    在日常一些需求中,总会遇到一些需要前端进行手动计算的场景,那么这里需要优先考虑的则是数字精度问题!具体请看下面截图如图所示,在JavaScript进行浮点型数据计算当中,会出现计算结果“不正确”的现象。我们知道浮点型数据类型主要有:单精度float、双精度double。浮点型简单来说就是表示......
  • 23级ACM第二次招新测试题解
    A.lyynuu思路:先了解子序列的概念:在数学中,某个序列的子序列是从最初序列通过去除某些元素但不破坏余下元素的相对位置(在前或在后)而形成的新序列接下来我们就思考什么样的字符串可以让子序列lynu形成的数量最多,显然当相同字符连在一起时可以形成尽可能多的lynu,例如:llyy......
  • 题解 P4755 Beautiful Pair
    洛谷。题意显然。分析首先考虑到分治,那么问题就在于如何维护经过某个结点的方案数。利用从中间结点向两端的前缀后缀最大值,接下来我们对左端点的每一个结点考虑连向右侧的方案数。考虑分类讨论,令左端点为\(i\),右端点为\(j\)。假如\(mx_i>mx_j\),那么我们整个区间的最大......