题解 tree
为啥就我不会签到题啊
首先发现只需要考虑 dfs 序相邻的点的 lca
然后发现可以启发式合并维护子树内的点,
通过在合并时找前驱后继找到每个点分属不同子树的 dfs 序相邻的点对
然后每个点可以按深度分层
可以产生贡献的条件是某个深度有点对被完全包含
离线下来扫描线即可
复杂度
点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 100010
#define fir first
#define sec second
#define pb push_back
#define ll long long
//#define int long long
char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
int ans=0, f=1; char c=getchar();
while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
return ans*f;
}
int n, m;
ll val[N], uni[N];
int head[N], fa[21][N], lg[N], dep[N], id[N], ecnt, tot, usiz;
struct edge{int to, next; ll val;}e[N<<1];
inline void add(int s, int t, ll w) {e[++ecnt]={t, head[s], w}; head[s]=ecnt;}
void dfs1(int u, int pa) {
id[u]=++tot;
for (int i=1; dep[u]>=1<<i; ++i)
fa[i][u]=fa[i-1][fa[i-1][u]];
for (int i=head[u],v; ~i; i=e[i].next) {
v = e[i].to;
if (v==pa) continue;
fa[0][v]=u;
dep[v]=dep[u]+1;
val[v]=val[u]+e[i].val;
dfs1(v, u);
}
}
int lca(int a, int b) {
if (dep[a]<dep[b]) swap(a, b);
while (dep[a]>dep[b]) a=fa[lg[dep[a]-dep[b]]-1][a];
if (a==b) return a;
for (int i=lg[dep[a]]-1; ~i; --i)
if (fa[i][a]!=fa[i][b])
a=fa[i][a], b=fa[i][b];
return fa[0][a];
}
namespace task1{
int sta[N], top;
void solve() {
for (int i=1,l,r; i<=m; ++i) {
l=read(); r=read(); top=usiz=0;
for (int j=l; j<=r; ++j) sta[++top]=j;
sort(sta+1, sta+top+1, [](int a, int b){return id[a]<id[b];});
for (int j=1; j<=top; ++j) uni[++usiz]=val[sta[j]];
for (int j=2; j<=top; ++j) uni[++usiz]=val[lca(sta[j-1], sta[j])];
sort(uni+1, uni+usiz+1);
usiz=unique(uni+1, uni+usiz+1)-uni-1;
printf("%d\n", usiz);
}
}
}
namespace task{
set<int> s[N];
int bit[N], pos[N], ans[5*N];
vector<pair<int, int>> add[N], que[N];
inline void upd(int i, int dat) {for (; i<=n; i+=i&-i) bit[i]+=dat;}
inline int query(int i) {int ans=0; for (; i; i-=i&-i) ans+=bit[i]; return ans;}
void dfs(int u, int fa) {
s[u].insert(u);
// cout<<"val: "<<val[u]<<endl;
int dep=lower_bound(uni+1, uni+usiz+1, val[u])-uni;
add[u].pb({u, dep});
for (int i=head[u],v; ~i; i=e[i].next) {
v = e[i].to;
if (v==fa) continue;
dfs(v, u);
if (s[v].size()>s[u].size()) swap(s[u], s[v]);
for (auto it:s[v]) {
auto suf=s[u].lower_bound(it);
if (suf!=s[u].end()) add[it].pb({*suf, dep});
if (suf!=s[u].begin()) add[*--suf].pb({it, dep});
}
for (auto it:s[v]) s[u].insert(it);
}
}
void solve() {
for (int i=1; i<=n; ++i) uni[++usiz]=val[i];
sort(uni+1, uni+usiz+1);
usiz=unique(uni+1, uni+usiz+1)-uni-1;
dfs(1, 0);
for (int i=1,l,r; i<=m; ++i) {
l=read(); r=read();
que[l].pb({r, i});
}
for (int i=n; i; --i) {
// cout<<"i: "<<i<<endl;
for (auto it:add[i]) {
// cout<<"dep: "<<it.sec<<endl;
if (!pos[it.sec]) upd(pos[it.sec]=it.fir, 1);
else if (it.fir<pos[it.sec]) upd(pos[it.sec], -1), upd(pos[it.sec]=it.fir, 1);
}
for (auto it:que[i]) ans[it.sec]=query(it.fir);
}
for (int i=1; i<=m; ++i) printf("%d\n", ans[i]);
}
}
signed main()
{
freopen("tree.in", "r", stdin);
freopen("tree.out", "w", stdout);
n=read(); m=read();
memset(head, -1, sizeof(head));
for (int i=1; i<=n; ++i) lg[i]=lg[i-1]+(1<<lg[i-1]==i);
for (int i=1,u,v,w; i<n; ++i) {
u=read(); v=read(); w=read();
add(u, v, w); add(v, u, w);
}
dep[1]=1; dfs1(1, 0);
// task1::solve();
task::solve();
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
2021-06-18 题解 星际旅行