P4556 [Vani有约会]雨天的尾巴 /【模板】线段树合并

线段树合并

线段树合并即合并两颗权值线段树,合并方法非常简单

但是这道题我调了很久

原因:数组开小了QAQ

线段树合并一般数组开\(3nlogn\)(更大也无伤大雅)

我\(ls\),\(rs\)数组开小了,导致玄学错误,结果晕头转向,最后才发现数组开小了

\(C++\)数组开小很多情况下不报错,因为它去调用其他数组的无用空间了,以至于难以发现错误

下次看到难以理解的错误(比如输出值在更改一个无关紧要的语句后不恒定),一定要去看数组(一个数组一个数组看过来)!

同时,可以将相同种类的数组放在一起

放代码吧。。。

#include<bits/stdc++.h>
#define N 200005
#define S 100000
#define pr pair<int,int>
using namespace std;
int n,m,x,y;
int cnt,tot,head[N],nxt[N],d[N],ac[N],lca[N],F[N],rt[N],ans[N];
int ls[N*25],rs[N*25],tree[N*25],id[N*25];
bool leaf[N*25];
vector<pr>q[N];
struct node
{
	int x,y,z;
}e[N];
void add(int x,int y)
{
	tot++;
	d[tot]=y;
	nxt[tot]=head[x];
	head[x]=tot;
}
int getf(int x)
{
	if (ac[x]==x)
		return x;
	return ac[x]=getf(ac[x]);
}
void tarjan(int u,int f)
{
	ac[u]=u;
	for (int i=head[u];i;i=nxt[i])
	{
		int v=d[i];
		if (v==f)
			continue;
		tarjan(v,u);
		ac[v]=u;
		F[v]=u;
	}
	for (vector<pr>::iterator it=q[u].begin();it!=q[u].end();it++)
		if (ac[it->first])
			lca[it->second]=getf(ac[it->first]);
}
void change(int &p,int l,int r,int x,int z)
{
	if (!p)
		p=++cnt;
	if (l==r)
	{
		tree[p]+=z;
		id[p]=l;
		leaf[p]=true;
		return;
	}
	int mid=(l+r) >> 1;
	if (x<=mid)
		change(ls[p],l,mid,x,z); else
		change(rs[p],mid+1,r,x,z);
	if (tree[ls[p]]>tree[rs[p]]||tree[ls[p]]==tree[rs[p]]&&id[ls[p]]<id[rs[p]])
	{
		tree[p]=tree[ls[p]];
		id[p]=id[ls[p]];
	} else
	{
		tree[p]=tree[rs[p]];
		id[p]=id[rs[p]];
	}
}
int merge(int x,int y)
{
	if (!x||!y)
		return x|y;
	if (leaf[x]&&leaf[y])
	{
		tree[x]+=tree[y];
		return x;
	}
	ls[x]=merge(ls[x],ls[y]);
	rs[x]=merge(rs[x],rs[y]);
	if (tree[ls[x]]>tree[rs[x]]||tree[ls[x]]==tree[rs[x]]&&id[ls[x]]<id[rs[x]])
	{
		tree[x]=tree[ls[x]];
		id[x]=id[ls[x]];
	} else
	{
		tree[x]=tree[rs[x]];
		id[x]=id[rs[x]];
	}
	return x;
}
void dfs(int u)
{
	for (int i=head[u];i;i=nxt[i])
	{
		int v=d[i];
		if (v==F[u])
			continue;
		dfs(v);
		rt[u]=merge(rt[u],rt[v]);
	}
	ans[u]=id[rt[u]];
}
int main() 
{
	scanf("%d%d",&n,&m);
	for (int i=1;i<n;i++)
	{
		scanf("%d%d",&x,&y);
		add(x,y);
		add(y,x);
	}
	for (int i=1;i<=m;i++)
	{
		scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].z);
		q[e[i].x].push_back(make_pair(e[i].y,i));
		q[e[i].y].push_back(make_pair(e[i].x,i));
	}
	tarjan(1,0);
	for (int i=1;i<=m;i++)
	{
		change(rt[e[i].x],1,S,e[i].z,1);
		change(rt[e[i].y],1,S,e[i].z,1);
		change(rt[lca[i]],1,S,e[i].z,-1);
		if (F[lca[i]])
			change(rt[F[lca[i]]],1,S,e[i].z,-1);
	}
	dfs(1);
	for (int i=1;i<=n;i++)
		printf("%d\n",ans[i]);
	return 0;
}
上一篇:[Vani有约会]雨天的尾巴 - 线段树合并


下一篇:[ Vani有约会 ] 雨天的尾巴 /【模板】线段树合并