HDU 5893 List wants to travel(树链剖分+线段树)

题目链接 HDU5893

$2016$年$ICPC$沈阳网络赛的$B$题。这道题其和 BZOJ2243 基本一样

那道题我也写了题解 点这里

两道题的区别就是$BZOJ$这题是点的权值,这道题是边权。

所以我们把边权看成这条边连接的两个点的深度较大的那条边的点权就可以了。

但是这样的话根结点就没有权值了。

询问和查询的时候,若$x$和$y$的$LCA$为$t$,

那么我们从$x$出发往上爬,爬到$X'$,使得$deep[X'] - deep[t] = 1$

同样我们从$y$出发往上爬,爬到$Y'$,使得$deep[Y'] - deep[t] = 1$

于是一个询问被我们拆成了两个,一个查询也被我们拆成了两个。

然后依次处理就好了。

当$x$是$y$的祖先,或者$y$是$x$的祖先的时候,特判下即可。

#include <bits/stdc++.h>

using namespace std;

#define rep(i, a, b)    for (int i(a); i <= (b); ++i)
#define dec(i, a, b)    for (int i(a); i >= (b); --i)
#define lson        i << 1, L, mid
#define rson        i << 1 | 1, mid + 1, R
#define MP        make_pair
#define fi        first
#define se        second

typedef long long LL;
typedef pair<int, int> PII;

const int N = 5e4 + 10;
const int A = 19;

vector <PII> v[N];
int father[N], deep[N], c[N], sz[N], son[N], f[N], top[N];
int lazy[N << 2], s[N << 2], lc[N << 2], rc[N << 2];
int st[N][A];
int n, m, tot;
char op[10];

void dfs(int x, int fa, int dep, int val){
	sz[x] = 1;
	father[x] = fa;
	deep[x] = deep[fa] + 1;
	c[x] = val;

	if (fa){ 
		st[x][0] = fa;
		for (int i = 0; st[st[x][i]][i]; ++i) st[x][i + 1] = st[st[x][i]][i];
	}

	for (auto cnt : v[x]){
		int u = cnt.fi, w = cnt.se;
		if (u == fa) continue;
		dfs(u, x, dep + 1, w);
		sz[x] += sz[u];
		if (sz[son[x]] < sz[u]) son[x] = u;
	}
}

void dfs2(int x, int tp){
	f[x] = ++tot;
	top[x] = tp;
	if (son[x]) dfs2(son[x], tp);

	for (auto cnt : v[x]){
		int u = cnt.fi, w = cnt.se;
		if (u == father[x] || u == son[x]) continue;
		dfs2(u, u);
	}
}

int LCA(int x, int y){
	for (; top[x] ^ top[y]; ){
		if (deep[top[x]] < deep[top[y]]) swap(x, y);
		x = father[top[x]];
	}

	return deep[x] > deep[y] ? y : x;
}

inline int updis(int x, int dis){
	dec(i, 17, 0) if ((1 << i) & dis) x = st[x][i], dis ^= (1 << i);
	return x;
}

inline void pushup(int i){
	lc[i] = lc[i << 1];
	rc[i] = rc[i << 1 | 1];
	if (rc[i << 1] ^ lc[i << 1 | 1]) s[i] = s[i << 1] + s[i << 1 | 1];
	else s[i] = s[i << 1] + s[i << 1 | 1] - 1;
}

inline void pushdown(int i, int L, int R){
	int tmp = lazy[i];
	if (tmp == -1 || L == R) return;

	s[i << 1]      = s[i << 1 | 1]    = 1;
	lazy[i << 1]   = lazy[i << 1 | 1] = tmp;

	lc[i << 1]     = rc[i << 1]       = tmp;
	lc[i << 1 | 1] = rc[i << 1 | 1]   = tmp;
	lazy[i] = -1;
}

void build(int i, int L, int R){
	s[i] = 1;
	lazy[i] = -1;

	if (L == R) return;
	int mid = (L + R) >> 1;

	build(lson);
	build(rson);
}

void change(int i, int L, int R, int l, int r, int val){
	pushdown(i, L, R);
	if (L == l && R == r){
		lc[i] = rc[i] = val;
		s[i]  = 1;
		lazy[i] = val;
		return;
	}

	int mid = (L + R) >> 1;
	if (r <= mid) change(lson, l, r, val);
	else if (l > mid) change(rson, l, r, val);
	else{
		change(lson, l, mid, val);
		change(rson, mid + 1, r, val);
	}

	pushup(i);
}

int query(int i, int L, int R, int l, int r){
	pushdown(i, L, R);
	if (L == l && R == r) return s[i];

	int mid = (L + R) >> 1;
	if (r <= mid) return query(lson, l, r);
	else if (l > mid) return query(rson, l, r);
	else{
		int tmp = 1;
		if (rc[i << 1] ^ lc[i << 1 | 1]) tmp = 0;
		return query(lson, l, mid) + query(rson, mid + 1, r) - tmp;
	}
}

int getcolor(int i, int L, int R, int x){
	pushdown(i, L, R);
	if (L == R) return lc[i];
	int mid = (L + R) >> 1;
	if (x <= mid) return getcolor(lson, x);
	else return getcolor(rson, x);
}

int solvesum(int x, int tp){
	int ret = 0;
	for (; top[x] ^ top[tp] ;){
		ret += query(1, 1, n, f[top[x]], f[x]);
		if (getcolor(1, 1, n, f[top[x]]) == getcolor(1, 1, n, f[father[top[x]]])) --ret;
		x = father[top[x]];
	}

	ret += query(1, 1, n, f[tp], f[x]);
	return ret;
}

void solvechange(int x, int tp, int val){
	for (; top[x] ^ top[tp]; ){
		change(1, 1, n, f[top[x]], f[x], val);
		x = father[top[x]];
	}

	change(1, 1, n, f[tp], f[x], val);
}

int main(){

	while (~scanf("%d%d", &n, &m)){
		tot = 0;
		rep(i, 0, n + 1) v[i].clear();
		memset(st, 0, sizeof st);
		memset(f, 0, sizeof f);
		memset(father, 0, sizeof father);
		rep(i, 2, n){
			int x, y, z;
			scanf("%d%d%d", &x, &y, &z);
			v[x].push_back(MP(y, z));
			v[y].push_back(MP(x, z));
		}

		memset(son, 0, sizeof son);
		dfs(1, 0, 1, 0);
		dfs2(1, 1);

		memset(lc, 0, sizeof lc);
		memset(rc, 0, sizeof rc);
		build(1, 1, n);
		rep(i, 2, n) change(1, 1, n, f[i], f[i], c[i]);
		while (m--){
			scanf("%s", op);
			if (op[0] == 'Q'){
				int x, y;
				scanf("%d%d", &x, &y);
				if (x == y){
					puts("0");
					continue;
				}

				if (deep[x] < deep[y]) swap(x, y);
				int t = LCA(x, y);
				if (y == t){
					int yy = updis(x, deep[x] - deep[y] - 1);
					printf("%d\n", solvesum(x, yy));
					continue;
				}

				int xx = updis(x, deep[x] - deep[t] - 1);
				int yy = updis(y, deep[y] - deep[t] - 1);
				int reta = solvesum(x, xx);
				int retb = solvesum(y, yy);
				int ret;
				if (getcolor(1, 1, n, f[xx]) == getcolor(1, 1, n, f[yy]))
					ret = reta + retb - 1;
				else
					ret = reta + retb;
				printf("%d\n", ret);
			}

			else{
				int x, y, z;
				scanf("%d%d%d", &x, &y, &z);
				if (x == y) continue;

				if (deep[x] < deep[y]) swap(x, y);
				int t = LCA(x, y);
				if (y == t){
					int yy = updis(x, deep[x] - deep[y] - 1);
					solvechange(x, yy, z);
					continue;
				}

				int xx = updis(x, deep[x] - deep[t] - 1);
				int yy = updis(y, deep[y] - deep[t] - 1);

				solvechange(x, xx, z);
				solvechange(y, yy, z);            

			}
		}
	}

	return 0;
}

 

转载于:https://www.cnblogs.com/cxhscst2/p/7532940.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值