Codeforces Round #329 D Happy Tree Party(树链剖分)

题意:给出一棵树,每条边有一个权值,每次可以进行两种操作,第一种计算操作给出一个数y和结点u,v,计算y除以


从节点u到结点v之间所有数的商(向下取整),第二种操作是修改操作,将第i条边的权值修改为u。要求对于每一个询问输出结果。

思路:因为y分别除以(下取整)一条链上的所有数等价于y除以(下取整)这条链上所有数的积,所以可以用树链剖分来做,只不过数据范围比较大,用一个状态标记当前区间的积是否大于1e18,然后查询的时候类似如果大于1e18直接输出0即可,否则用y除以计算出来的乘积。

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define eps 1e-6
#define LL long long
#define pii pair
//#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;

const int MAXN = 200020;
int n, tot, q;
int tag[MAXN*4];
LL mul[MAXN*4];
void update(int o, int L, int R, int pos, LL v) {
	if(L==R) mul[o] = v;
	else {
		int M = (L+R) >> 1;
		if(pos <= M) update(o<<1, L, M, pos, v);
		else update((o<<1)|1, M+1, R, pos, v);
		if(tag[o<<1] | tag[(o<<1)|1]) tag[o] = 1;
		else {
			double tmp1 = mul[(o<<1)], tmp2 = mul[(o<<1)|1];
			if(tmp1*tmp2 > 1e18) tag[o] = 1;
			else mul[o] = mul[o<<1] * mul[(o<<1)|1], tag[o] = 0;
		}
	}
}
LL query(int o, int L, int R, int ql, int qr) {
	int M = (L+R) >> 1;
	LL flag1 = 1, flag2 = 1;
	if(ql<=L && qr>=R) return tag[o] ? -1 : mul[o];
	if(ql <= M) flag1 = query(o*2, L, M, ql, qr);
	if(M < qr) flag2 = query(o*2+1, M+1, R, ql, qr);
	if(flag1<0 || flag2<0) return -1;
	double t1 = flag1, t2 = flag2;
	if(t1*t2 > 1e18) return -1;
	return flag1 * flag2;
}
vector G[MAXN], W[MAXN];
int siz[MAXN], son[MAXN], dep[MAXN], top[MAXN], fa[MAXN], pos[MAXN];
void dfs(int cur, int f) {
	siz[cur] = 1;
	int tmp = 0;
	for(int i = 0; i < G[cur].size(); i++) {
		int u = G[cur][i];
		if(u == f) continue;
		dep[u] = dep[cur] + 1;
		fa[u] = cur;
		dfs(u, cur);
		siz[cur] += siz[u];
		if(siz[u] > tmp) son[cur] = u, tmp = siz[u];
	}
}
void dfs2(int cur, int tp) {
	top[cur] = tp;
	pos[cur] = ++tot;
	if(son[cur]) dfs2(son[cur], tp);
	for(int i = 0; i < G[cur].size(); i++) {
		int u = G[cur][i];
		if(u==son[cur] || u==fa[cur]) continue;
		dfs2(u, u);
	}
}
LL Find(LL u, LL v) {
	LL ans = 1, flag;
	int fu = top[u], fv = top[v];
	//cout << u << endl << v << endl;
	//cout << fu << endl << fv << endl;
	while(fu != fv) {
		if(dep[fu] 1e18) return -1;
		ans *= flag;
		u = fa[fu]; fu = top[u];
	}
	if(u==v) return ans;
	else if(dep[u] 1e18) return -1;
	ans *= flag;
	return ans;
}
LL edge[MAXN][3];
int main() {
    //freopen("input.txt", "r", stdin);
	cin >> n >> q;
	for(int i = 1; i < n; i++) {
		LL u, v, d;
		scanf("%I64d%I64d%I64d", &u, &v, &d);
		G[u].push_back(v);
		G[v].push_back(u);
		edge[i][0] = u;
		edge[i][1] = v;
		edge[i][2] = d;
	}
	dfs(1, 0);
	dfs2(1, 1);
	for(int i = 1; i <= n-1; i++) {
		LL& u = edge[i][0];
		LL& v = edge[i][1];
		if(dep[u] > dep[v]) swap(u, v);
		update(1, 1, n, pos[v], edge[i][2]);
	}
	for(int i = 1, op; i <= q; i++) {
		LL u, v, y;
		scanf("%d", &op);
		if(op == 1) {
			scanf("%I64d%I64d%I64d", &u, &v, &y);
			LL div = Find(u, v);
			//cout << div << endl;
			if(div < 0) puts("0");
			else printf("%I64d\n", y/div);
		}
		else {
			scanf("%I64d%I64d", &u, &y);
			update(1, 1, n, pos[edge[u][1]], y);
		}
	}
    return 0;
}

















你可能感兴趣的:(程序设计竞赛)