当前位置: 首页 > news >正文

做题随笔:P14521

Solution

题意

原题链接

感觉题意很难形式化,建议自己读一下。

大概是:给一个定根树,每个点有一个点权,每条边有一个可通过区间,从根开始,带着一个初值向下走,每到一个点把点权加在值上,对初值 \(x\)\(q\) 个取值求可达点数量。

注意:根节点算可达点,根节点的点权也要加上。

分析

首先有一个很自然的思路:对于一个可达点 \(u\),如果初值是 \(x\),从根到 \(u\) 的路径点权和是 \(s\),到达 \(u\) 时的值就是 \(x+s\)。于是对于 \(u\) 向下的边,如果它的可通过区间是 \([l,r]\),那么可以通过这条边的初值区间就是 \([l-s,r-s]\)

好的,其实就做完了。我们直接 dfs 一次计算根到所有点的路径点权,并计算可通过区间。注意一下每个点的可达区间应对父亲取交,毕竟要先到父亲才能到它。至于统计答案,我们需要做区间加,单点查,写个差分数组就完……了吗?

注意到 \(x \in [-1 \times 10^{18},1 \times 10^{18}]\),差分数组完全开不下。但是,我们发现:每个树上的点会做两次差分数组上的操作,所以只有 \(O(n)\) 个差分数组的位是有意义的,那我们只对这些位操作就行了。相当于是:我们“离散化”了差分数组。

具体地,开一个 vector,存 \(x,d\) 表示我需要在差分数组的 \(x\) 位上执行加 \(d\) 操作。查询离线一下,对 \(x\) 排序后扫,就扫完 \(x\) 及之前的求和就行(这好像叫扫描线是吧)。

Tip:注意要扔掉 \(l>r\) 的区间,不然差分数组会错。赛时蒟蒻就是这样调了 30min。

注意下路径点权和会爆 long long,记得开 int128。

Code

#include <iostream>
#include <cctype>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
#include <climits>typedef long long ll;ll fr() {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^48);c=getchar();}return x*f;
}struct node{ll i;int d;bool operator< (const node &n) const&{return i<n.i;}
};std::vector<node> v;//差分数组的 vectorconst int maxn=5e5+100;struct edge{int v,nxt;ll l,r;
}e[maxn<<1];int head[maxn],tot;void ade(int u,int v,ll l,ll r) {e[++tot]={v,head[u],l,r};head[u]=tot;
}ll a[maxn];void dfs(int u,__int128_t dx,ll fl,ll fr) {dx+=a[u];for(int i = head[u]; i; i=e[i].nxt) {__int128_t l=e[i].l,r=e[i].r;l+=dx,r+=dx;l=std::max((__int128_t)-1e18-100,l),r=std::min((__int128_t)1e18+100,r);//x 的范围只有这么大,多的不用管l=std::max((ll)l,fl),r=std::min((ll)r,fr);if(l>r) continue;v.push_back({(ll)l,1});v.push_back({(ll)r+1,-1});dfs(e[i].v,dx,l,r);}
}struct qry{ll x;int id,ans;
};bool cmp1(qry q1,qry q2) {return q1.x<q2.x;
}bool cmp2(qry q1,qry q2) {return q1.id<q2.id;
}qry Q[maxn<<1];int main() {int n=fr(),q=fr();v.reserve(n<<1);for(int i = 1; i < n; i++) {int p=fr();ll l=fr(),r=fr();ade(p,i+1,l,r);}for(int i = 1; i <= n; i++) a[i]=-fr();dfs(1,0,LLONG_MIN,LLONG_MAX);std::sort(v.begin(),v.end());for(int i = 1; i <= q; i++) Q[i]={fr(),i,0};std::sort(Q+1,Q+1+q,cmp1);int now=0;int p=0;for(int i = 1; i <= q; i++) {ll x=Q[i].x;while(p<v.size()&&v[p].i<=x) {now+=v[p].d;p++;}Q[i].ans=now;}std::sort(Q+1,Q+1+q,cmp2);for(int i = 1; i <= q; i++) printf("%d\n",Q[i].ans+1);return 0;
}

一些闲话

如果觉得有用,点个赞吧!

http://www.rkmt.cn/news/51387.html

相关文章:

  • Win11系统恢复经典的右键菜单方法(CMD快速执行)
  • 20251116
  • 选拔赛题解
  • C++ 中的 **普通筛、埃氏筛、线性筛**,它们都是求质数或判断质数的方法
  • 完整教程:Rust语言特性深度解析:所有权、生命周期与模式匹配之我见
  • 20231427田泽航第九周预习报告
  • 【2025-11-14】工作压力
  • 20232401 2024-2025-1 《网络与系统攻防技术》实验五实验报告
  • do文件仿真 fpga
  • [ sqlite ]
  • 视野修炼-技术周刊第127期 | Valdi
  • 完整教程:机器学习:基于大数据的基金数据分析可视化系统 股票数据 金融数据 股价 Django框架 大数据技术(源码) ✅
  • 【AIGC】语音识别ASR:火山引擎大模型技术实践 - 详解
  • 2025 年 11 月石笼网厂家最新推荐,技术实力与市场口碑深度解析!
  • 2025年11月温州律师事务所最新推荐,实力机构深度解析与择选指南!
  • 实用指南:spark组件-spark core(批处理)
  • 详细介绍:用Flux.1-Krea[dev]打造动漫风格插画的提示词灵感与创作技巧
  • 11 月 14 日
  • 2025-11-13~15 hetao1733837的刷题记录
  • 20251114周五日记
  • 11 月 7 日
  • Java 可变参数机制
  • C# 高级类型 Dictionary(学习笔记4)
  • Metasploit Framework 6.4.99 (macOS, Linux, Windows) - 开源渗透测试框架
  • 小程序获取OCR识别结果,示例代码
  • Acunetix v25.11 发布,新增功能简介
  • MySQL数据过滤与计算字段实战技术指南
  • 实用指南:【第五章:计算机视觉-项目实战之推荐/广告系统】1.推荐系统基础与召回算法-(6)召回算法之u2i: FM、deepFM、召回双塔原理精讲与实战
  • 实用指南:On-Page SEO完全指南:从关键词策略到内容优化
  • Java位运算符概览