树剖 40pts 求调
查看原帖
树剖 40pts 求调
756660
B612Dusk楼主2023/11/8 14:15

思路就是像染色一样每次染一条链,询问的时候分成 x->lca 和 (lca->y的下一级祖先) -> y,然后中间拼一下,但是不知道为什么挂了很多,答案里错的都是和正确的相差 1 或者 2,调不出来,球球。

去掉了文件头和快读等不必要的影响

int n, Cols, Q;

struct edges{
	int nxt, ver;
}edge[N << 1];

int head[N] ,tot;
inline void add(int a, int b)
{
	edge[++ tot] = {head[a], b};
	head[a] = tot;
}

int fa[N], sze[N], son[N], dep[N];
void get_son(int x, int Fa)
{
	fa[x] = Fa;
	sze[x] = 1;
	dep[x] = dep[Fa] + 1;
	for(int i = head[x]; i; i = edge[i].nxt)
	{
		int y = edge[i].ver;
		if(y == Fa)	 continue;
		get_son(y, x);
		sze[x] += sze[y];
		sze[son[x]] < sze[y] ? son[x] = y : y = y;
	}
}

int top[N], cnt, dfn[N], nfd[N];
void get_chain(int x, int Top)
{
	top[x] = Top;
	dfn[x] = ++ cnt;
	nfd[cnt] = x;
	if(!son[x])	 return;
	get_chain(son[x], Top);
	for(int i = head[x]; i ; i = edge[i].nxt)
	{
		int y = edge[i].ver;
		if(y == son[x] or y == fa[x])	 continue;
		get_chain(y, y);
	}
}

inline int LCA(int x, int y)
{
	while(top[x] != top[y])
	{
		if(dep[top[x]] < dep[top[y]])	swap(x, y);
		x = fa[top[x]];
	}
	return dep[x] < dep[y] ? x : y;
}

struct Seg{
	int l, r, lc, rc, sum, tag;
	#define l(p)	tree[p].l
	#define r(p)	tree[p].r
	#define lc(p)	tree[p].lc
	#define rc(p)	tree[p].rc
	#define tag(p)	tree[p].tag
	#define sum(p)	tree[p].sum
}tree[N << 2];

void build(int p, int l, int r)
{
	l(p) = l, r(p) = r, tag(p) = 0, lc(p) = 0, rc(p) = 0, sum(p) = 0;
	if(l == r)
	{
		lc(p) = rc(p) = dfn[l];
		sum(p) = 0;
		return ;
	}
	int mid = l + r >> 1;
	build(p << 1, l, mid);
	build(p << 1 | 1, mid + 1, r);
}

inline void Spread(int p)
{
	if(tag(p))
	{
		lc(p << 1) = lc(p << 1 | 1) = tag(p);
		rc(p << 1) = rc(p << 1 | 1) = tag(p);
		
		sum(p << 1) = r(p << 1) - l(p << 1);
		sum(p << 1 | 1) = r(p << 1 | 1) - l(p << 1 | 1);
		
		tag(p << 1) = tag(p << 1 | 1) = tag(p);
		tag(p) = 0;
	}
}

inline void update(int p)
{
	lc(p) = lc(p << 1), rc(p) = rc(p << 1 | 1);
	sum(p) = sum(p << 1) + sum(p << 1 | 1) + (lc(p << 1 | 1) == rc(p << 1));
}

void mtf(int p, int l, int r, int c)
{
	if(l(p) >= l and r(p) <= r)
	{
		tag(p) = c;
		sum(p) = r(p) - l(p);
		lc(p) = rc(p) = c;
		return;
	}
	Spread(p);
	int mid = l(p) + r(p) >> 1;
	if(l <= mid)	mtf(p << 1,l , r, c);
	if(r > mid)		mtf(p << 1 | 1, l, r, c);
	update(p);
}

struct area { int lc, rc, sum; };

area qry(int p, int l, int r) // 我关注的只有左端点,右端点 
{
	if(l(p) >= l and r(p) <= r)	return {lc(p), rc(p), sum(p)};
	Spread(p);
	int mid = l(p) + r(p) >> 1;
	area Val = {0, 0, 0};
	if(l <= mid)	Val = qry(p << 1, l, r);
	if(r > mid)
	{
		area Right = qry(p << 1 | 1, l, r);
		if(Val.lc)// 有左区间	
		{
			Val.sum += Right.sum + (Val.rc == Right.lc);
			Val.rc = Right.rc;
		}
		else	Val = Right;
	}
	return Val;
}

void ch_mtf(int x, int y, int c)
{
	while(top[x] != top[y])
	{
		if(dep[top[x]] < dep[top[y]])	swap(x, y);
		mtf(1, dfn[top[x]], dfn[x], c);
		x = fa[top[x]];
	}
	if(dep[x] > dep[y])	 swap(x, y);
	mtf(1, dfn[x], dfn[y], c);
}

#define pb emplace_back
vector<area> ls, rs;

// 由于链需要跨过 lca,我用了个分讨,跨过 lca 的我分成向上为左链, dep 大的为该链左边,右链相反

void ch_qry(int x, int lca, bool op) // 假如是两条链拼在一起,1 表示左链,0 表示右链 
{
	while(top[x] != top[lca])
	{
		area blo = qry(1, dfn[top[x]], dfn[x]);
		op ? ls.pb((area){blo.rc, blo.lc, blo.sum}) : rs.pb(blo);
		x = fa[top[x]];
	}
	area blo = qry(1, dfn[lca], dfn[x]);
	op ? ls.pb((area){blo.rc, blo.lc, blo.sum}) : rs.pb(blo);
}

inline int jmp(int x, int lca) // 下一级祖先
{
	while(top[x] != top[lca])
	{
		if(fa[top[x]] == lca)	return top[x];
		x = fa[top[x]];
	}
	return nfd[dfn[lca] + 1];
}

int ch_cut(int x, int y) // 记住,左链从前向扫,右链从后向前扫 
{
	int lca = LCA(x, y), Ans = 0;
	int jp = jmp(y, lca);
	
	if(lca == x or lca == y)
	{
		if(dep[x] < dep[y])	 swap(x, y);
		ch_qry(x, y, 1);
	}
	
	else	ch_qry(x, lca, 1), ch_qry(y, jp, 0); // 右边只让跳到 jp 
	Ans += ls[0].sum;
	
	for(int i = rs.size() - 1;i >= 0; -- i)
		ls.pb(rs[i]), rs.pop_back();
	
	for(int i = 1;i < ls.size();i = -~i)
		Ans += ls[i].sum + (ls[i - 1].rc == ls[i].lc);
	
	for(int i = ls.size() - 1;i >= 0; -- i)
		ls.pop_back(); // 清空
	
	return Ans; 
}

inline void work()
{
	n = read(), Q = read();
	for(int i = 1;i < n;i = -~i)
	{
		int a = read(), b = read();
		add(a, b), add(b, a);
	}
	
	get_son(1, 1);
	get_chain(1, 1);
	build(1, 1, n);
	
	Cols = n;
	while(Q --)
	{
		int op = read();
		if(op == 1)
		{
			int x = read(), y = read();
			ch_mtf(x, y, ++ Cols);
		}
		else
		{
			int x = read(), y = read();
			printf("%lld\n", ch_cut(x, y));
		}
	}
}

inline void clears()
{
	memset(head, 0, sizeof head);
	memset(sze, 0, sizeof sze);
	memset(son, 0, sizeof son);
	memset(dep, 0, sizeof dep);
	cnt = 0, tot = 0, Cols = 0;
}

signed main()
{
	int T = read();
	while(T --)
	{
		work();
		clears();
	}
	return 0;
}
2023/11/8 14:15
加载中...