题解 tree

传送门

为啥就我不会签到题啊

首先发现只需要考虑 dfs 序相邻的点的 lca
然后发现可以启发式合并维护子树内的点,
通过在合并时找前驱后继找到每个点分属不同子树的 dfs 序相邻的点对
然后每个点可以按深度分层
可以产生贡献的条件是某个深度有点对被完全包含
离线下来扫描线即可
复杂度 O(nlog2n+mlogn)

点击查看代码
#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;
}
posted @   Administrator-09  阅读(2)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
历史上的今天:
2021-06-18 题解 星际旅行
点击右上角即可分享
微信分享提示