1. 程式人生 > 實用技巧 >P4556 [Vani有約會]雨天的尾巴 /【模板】線段樹合併

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;
}