题目链接


题目大意:

就是给你一个有根树,每个点都有一个编号,编号是它们的dfsdfsdfs序,现在qqq次询问,每次询问给你一个点vvv和一个区间[l,r][l,r][l,r],问你,这个区间里面的叶子节点,距离vvv最近的距离是多少?

每条边是有边权的

n,q∈[1,5e5]n,q\in[1,5e5]n,q∈[1,5e5]


解题思路:

  1. 首先我开始想在线处理但是太麻烦了。
  2. 对于这么多询问的还不强制在线的多半是离线处理!!
  3. 根据dfsdfsdfs序我们很容易联想到线段树,唉这里还有个区间查询。
  4. 那么我们可以把询问按照uuu进行分类,假设uuu为根就是线段树里面查询[l,r][l,r][l,r]的最小值
  5. 但是你去枚举根的时候很块超时了
  6. 那么我们就想到了换根
  7. 我们看一下每个节点nownownow和父亲节点的关系,就是从fa→nowfa\rightarrow nowfa→now的时候,nownownow这个子树里面的所有的叶子节点都要减掉edge[fa→now].wedge[fa\rightarrow now].wedge[fa→now].w,其他区间加上这个www
  8. 那么这个问题就愉快的解决了time:O((n+q)logn)time:O((n+q)logn)time:O((n+q)logn)

AC code

#include <bits/stdc++.h>
#define mid ((l + r) >> 1)
#define Lson rt << 1, l , mid
#define Rson rt << 1|1, mid + 1, r
#define ms(a,al) memset(a,al,sizeof(a))
#define log2(a) log(a)/log(2)
#define lowbit(x) ((-x) & x)
#define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define INF 0x3f3f3f3f
#define LLF 0x3f3f3f3f3f3f3f3f
#define f first
#define s second
#define endl '\n'
using namespace std;
const int N = 2e6 + 10, mod = 1e9 + 9;
const int maxn = 500010;
const long double eps = 1e-5;
const int EPS = 500 * 500;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PII;
typedef pair<ll,ll> PLL;
typedef pair<double,double> PDD;
template<typename T> void read(T &x) {x = 0;char ch = getchar();ll f = 1;while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}
template<typename T, typename... Args> void read(T &first, Args& ... args) {read(first);read(args...);
}
struct node {int id, l, r;
};
int n, q;
vector<node> G[maxn];
ll ans[maxn];
vector<pair<int,ll> > mp[maxn];struct Segtree {ll lazy[maxn << 2], tr[maxn << 2], arr[maxn];void pushup(int rt) {tr[rt] = min(tr[rt<<1],tr[rt<<1|1]);}void pushdown(int rt) {lazy[rt<<1] += lazy[rt];  lazy[rt<<1|1] += lazy[rt];  tr[rt<<1] += lazy[rt]; tr[rt<<1|1] += lazy[rt];lazy[rt] = 0; }void build(int rt, int l, int r) {lazy[rt] = 0;if(l == r) {tr[rt] = arr[l];return;}build(Lson);build(Rson);pushup(rt);}void update(int rt, int l, int r, int posl, int posr,ll val) {if(posl > posr) return;if(posl <= l && posr >= r) {tr[rt] += val;lazy[rt] += val;return;}pushdown(rt);if(posl <= mid) update(Lson,posl,posr,val);if(posr > mid) update(Rson,posl,posr,val);pushup(rt);}ll ask(int rt, int l, int r, int posl, int posr) {if(posl <= l && posr >= r) return tr[rt];pushdown(rt);ll res = LLF;if(posl <= mid) res = min(res,ask(Lson,posl,posr));if(posr > mid) res = min(res,ask(Rson,posl,posr)); return res;}
}sgt;int L[maxn], R[maxn], tot;
inline void dfs(int u, int fa, ll length) {sort(mp[u].begin(),mp[u].end());L[u] = ++ tot;for(auto it : mp[u]) {if(it.first == fa) continue;dfs(it.first,u,length+it.second);}R[u] = tot;if(L[u] == R[u]) sgt.arr[u] = length;//处理出所有叶子节点else sgt.arr[u] = LLF;
}inline void dfs2(int u, int fa) {for(auto it : G[u]) ans[it.id] = sgt.ask(1,1,n,it.l,it.r);for(auto it : mp[u]) {if(it.first == fa) continue;sgt.update(1,1,n,1,L[it.first]-1,it.second); // [1,L-1]sgt.update(1,1,n,R[it.first]+1,n,it.second); // [R+1,n]sgt.update(1,1,n,L[it.first],R[it.first],-it.second); // [L,R]dfs2(it.first,u);sgt.update(1,1,n,1,L[it.first]-1,-it.second);// 还原sgt.update(1,1,n,R[it.first]+1,n,-it.second);sgt.update(1,1,n,L[it.first],R[it.first],it.second);}
}int main() {IOS;cin >> n >> q;for(int i = 2; i <= n; ++ i) {int u;ll v;cin >> u >> v;mp[u].push_back({i,v});mp[i].push_back({u,v});}for(int i = 1; i <= q; ++ i) {int tag, l, r;cin >> tag >> l >> r;G[tag].push_back({i,l,r});}dfs(1,0,0);sgt.build(1,1,n);//建树dfs2(1,0);//求答案for(int i = 1; i <= q; ++ i) cout << ans[i] << endl;
}

线段树 + 树形换根 + dfs序 ---- 离线启发式求解 (有点像树上启发式合并答案) F. Nearest Leaf相关推荐

  1. 【XSY3549】Tree(线段树,换根)

    原题不想说(太懒了),就说一下总结到的两点想法? 对于树上多次询问路径信息的问题,如果两条路径的信息无法快速合并(即不能 pushup),但是在路径两端增加/删除单点后的信息变化可以快速得出,可以试一 ...

  2. jzoj3919-志愿者【换根法,线段树,树形dp】

    正题 题目链接:https://jzoj.net/senior/#main/show/3919 题目大意 nnn个点kkk个需要到达的点,然后求每个点出发经过这些点的最短路径. 解题思路 因为不用回去 ...

  3. 树的遍历顺序 - dfs序|欧拉序|dfn序(备忘)

    (仅作备忘) dfs序是dfs过程中对于某节点进入这个节点的子树和离开子树的顺序 满足每个节点都会在dfs序上出现恰好两次 任意子树的dfs序都是连续的 欧拉序是dfs过程中经过节点的顺序 每个节点至 ...

  4. CF 1324-F Maximum White Subtree //树形换根dp

    题目链接 http://codeforces.com/problemset/problem/1324/F 题意 给你一棵树( n n n 个顶点)和一个数组 a i a_i ai​,每个顶点要不是白色 ...

  5. 小G砍树 (换根dp)

    小G砍树 给你一棵n个节点的带标号无根树.每次,你可以选择一个度数为1的节点并将它从树上移除.问总共有多少种不同的方式能将这棵树删到只剩 1 个点.两种方式不同当且仅当至少有一步被删除的节点不同. 思 ...

  6. 树形dp ---- 树形换根dp F - The Maximum Subtree

    题目链接 题目大意: 给定一颗树,求这个树的最大子树,且这个子树是一个good-tree. good-tree的定义是:每个节点可以表示成一个数值区间,而树上的边表示两个点表示的数值区间相交 解题思路 ...

  7. hdu4417:线段树单点更新区间求和,离线 Super Mario

    Description Mario is world-famous plumber. His "burly" figure and amazing jumping ability ...

  8. BZOJ2588 Count on a tree DFS序+LCA+值域主席树

    Count on a tree 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权.其中lastans是上一个询问的答 ...

  9. 简单dfs序 + 树链剖分

    树链剖分 DFS序 先来讲一讲DFS序是什么东西,直接上图,方便理解. 估计巨巨们应该知道了DFS序的两个重要的东西,in,outin,outin,out数组. ininin数组就是这个点进入DFS的 ...

最新文章

  1. linux内核开发_Linux 内核的代码仓库管理与开发流程简介
  2. 1.0jpa 2.0_在JPA 2.1中使用@Convert正确完成映射枚举
  3. 在减少对内地房地产投资的同时,加快了在内地零售业的布局;并积极推动“走出去”战略,在全球52个国家投资多种业务。...
  4. Ubuntu下使用UFW配置防火墙(简化iptables的操作)
  5. Provisional headers are shown问题
  6. Flutter功能 之去除AppBar 阴影
  7. python改错题重要的事情说三遍_5个很好的Python面试题问题答案及分析
  8. 线性同余法随机数生成
  9. 数据报表体系搭建流程
  10. 商用密码产品认证-IPSec/SSL网关技术与产品
  11. 单片机输入和输出模式简要说明
  12. ioDraw - 免费的在线图表制作工具
  13. Leetcode2057. 值相等的最小索引
  14. matlab绘制风场图(矢量图、箭头图)
  15. [资料分享] 深受电子工程师喜爱的电路资料大合集
  16. OpenCV—Python 相似图像搜索算法
  17. RoboMongo简单安装和操作
  18. Subsonic的使用之基本语法、操作
  19. html5中动画总结,前端动画总结
  20. Spring Security 详解与实操第一节 认证体系与密码安全

热门文章

  1. Windows系统下的 vbs病毒生成器使用方法!
  2. 静态路由和默认路由的区别
  3. 二值化算法OTSU源码解析
  4. 人脸识别剩下的难题:从遮挡,年龄,姿态,妆造到亲属关系,人脸攻击
  5. 基于OpenCV实战:对象跟踪
  6. 我仅使用到的dd if
  7. 第四章:Spring项目文件上传两种方式(全解析)
  8. CPU状态信息us,sy,ni,id,wa,hi,si,st含义
  9. kali系统破解WPA密码实战
  10. javascript的typeof返回哪些数据类型