码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2017-09-16 23:23:19      阅读:244      评论:0      收藏:0      [点我收藏+]

标签:else   www.   etc   air   ++   ref   cpp   ack   targe   

题目链接 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;
}

 

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

标签:else   www.   etc   air   ++   ref   cpp   ack   targe   

原文地址:http://www.cnblogs.com/cxhscst2/p/7532940.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!