您的位置:首页 > 移动开发

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

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

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

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

#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<vector>
#include<map>
#include<queue>
#include<stack>
#include<string>
#include<map>
#include<set>
#include<ctime>
#define eps 1e-6
#define LL long long
#define pii pair<int, int>
//#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<LL> 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]<dep[fv]) swap(fu, fv), swap(u, v);
//cout << pos[fu] << " " << pos[u] << endl;
flag = query(1, 1, n, pos[fu], pos[u]);
//cout << flag << endl;
if(flag < 0) return -1;
double t1 = flag, t2 = ans;
if(t1*t2 > 1e18) return -1;
ans *= flag;
u = fa[fu]; fu = top[u];
}
if(u==v) return ans;
else if(dep[u]<dep[v]) swap(u, v);
flag = query(1, 1, n, pos[v]+1, pos[u]);
if(flag < 0) return -1;
double t1 = flag, t2 = ans;
if(t1*t2 > 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;
}

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  codeforces 树链剖分