题目链接 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(树链剖分+线段树)的更多相关文章

  1. HDU 2460 Network(双连通+树链剖分+线段树)

    HDU 2460 Network 题目链接 题意:给定一个无向图,问每次增加一条边,问个图中还剩多少桥 思路:先双连通缩点,然后形成一棵树,每次增加一条边,相当于询问这两点路径上有多少条边,这个用树链 ...

  2. Aragorn's Story 树链剖分+线段树 && 树链剖分+树状数组

    Aragorn's Story 来源:http://www.fjutacm.com/Problem.jsp?pid=2710来源:http://acm.hdu.edu.cn/showproblem.p ...

  3. 【BZOJ-2325】道馆之战 树链剖分 + 线段树

    2325: [ZJOI2011]道馆之战 Time Limit: 40 Sec  Memory Limit: 256 MBSubmit: 1153  Solved: 421[Submit][Statu ...

  4. 【BZOJ2243】[SDOI2011]染色 树链剖分+线段树

    [BZOJ2243][SDOI2011]染色 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的 ...

  5. BZOJ2243 (树链剖分+线段树)

    Problem 染色(BZOJ2243) 题目大意 给定一颗树,每个节点上有一种颜色. 要求支持两种操作: 操作1:将a->b上所有点染成一种颜色. 操作2:询问a->b上的颜色段数量. ...

  6. POJ3237 (树链剖分+线段树)

    Problem Tree (POJ3237) 题目大意 给定一颗树,有边权. 要求支持三种操作: 操作一:更改某条边的权值. 操作二:将某条路径上的边权取反. 操作三:询问某条路径上的最大权值. 解题 ...

  7. bzoj4034 (树链剖分+线段树)

    Problem T2 (bzoj4034 HAOI2015) 题目大意 给定一颗树,1为根节点,要求支持三种操作. 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子 ...

  8. HDU4897 (树链剖分+线段树)

    Problem Little Devil I (HDU4897) 题目大意 给定一棵树,每条边的颜色为黑或白,起始时均为白. 支持3种操作: 操作1:将a->b的路径中的所有边的颜色翻转. 操作 ...

  9. Aizu 2450 Do use segment tree 树链剖分+线段树

    Do use segment tree Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://www.bnuoj.com/v3/problem_show ...

  10. 【POJ3237】Tree(树链剖分+线段树)

    Description You are given a tree with N nodes. The tree’s nodes are numbered 1 through N and its edg ...

随机推荐

  1. No package python-pip available

    因为没有此rpm包,此包包含在epel源里面 输入rpm -ivh http://dl.fedoraproject.org/pub/epel/6/i386/epel-release-6-8.noarc ...

  2. SpringMVC+Spring+Mybatis整合程序之整合

    因为每个人思路不一样,所以我在这边先分享自己的思路对于mybatis开发持久层(DAO:DataBase Access Object 持久层访问对象)有两种.第一种:传统的开发持久层方式即需要程序员开 ...

  3. FTP文传协议的应用

    我开发的项目中一直用到都是AFNetworking上传图片的方法,最近老大说要用FTP上传,网上的资料很少,毕竟这种上传方式现在用的不多了,于是花了一天时间学习了FTP文件传输协议.下面是我的个人理解 ...

  4. hihoCoder-1109-堆优化的Prim

    优先队列是由堆组成的,所以当我们使用优先队列对Prim进行优化时,就把这种优化叫做堆优化. 它的算法核心思想就是每次向后找边,每个pair存的都是下一个点,以及边权.我们对于已经走过的点就避开,这样就 ...

  5. 前端上传控件plupload总结

    plupload是一个单图和多图上传控件: 属性和方法介绍,参考以下博客: https://www.cnblogs.com/2050/p/3913184.html 这里直接贴出JS代码,细到爆的注释, ...

  6. Pycharm快捷键及Python常用转义符

    不管是windows.xshell或者pycharm,学会使用快捷键都会使学习工作达到事半功倍的效果.这篇博客收集了部分常用的pycharm快捷键,分享给大家,希望对大家有用. 1. 常用快捷键 Py ...

  7. linux中mysql自带同步

    今天打算给一个做主备web服务器.考虑到数据库的同步,现在自己本地虚拟机做个实验. 经过慎重考虑(其实就是参考了下论坛大家的看法). 最后决定用mysql自带的同步设置. 话不多说 配置过程如下.

  8. Day13有参装饰器,三元表达式,匿名函数

    多个装饰器: 加载顺序:由下而上 执行顺序:由上而下 有参装饰器: 闭包,给函数传参的一种方法 当装饰器内需要参数时,可以采用闭包形式给其传参,第三层函数接收完参数时,就变为无参装饰器 三元表达式: ...

  9. PyCharm 社区版创建Django项目的一个方法

    PyCharm 社区版创建项目无法选择Django等项目,只能选择Python项目. 你在进行练习的时候为了方便,可以用过期了的PyCharm专业版在可用的30分钟内创建社区版本不支持的项目,再用Py ...

  10. Luogu3195 [HNOI2008]玩具装箱TOY (方程变形 + 斜率优化 )

    题意: 给出一个序列 {a[i]} 把其分成若干个区间,每个区间的价值为 W = (j − i + ∑ak(i<=k<=j) - L)​2 ,求所有分割方案中价值之和的最小值. 细节: 仔 ...