题目链接 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. Jarvis OJ-Level4

    借助DynELF实现无libc的漏洞利用小结 #!/usr/bin/env python # coding:utf-8 from pwn import * elf = ELF('level4') wr ...

  2. 第九次第十次作业 网页设计HTML语言之mp3 与mp4音频与视频两次作业,功能在一起也可

    参考的网址是: MP3 参考http://www.cnblogs.com/qingyundian/p/7831098.html MP4参考 http://www.cnblogs.com/qingyun ...

  3. cocos2d popSceneWithTransition()方法

    要在CCDirector.h中增加如下方法: template <typename T> void popSceneWithTransition(float t) { CCASSERT(_ ...

  4. Xcode中的约束用法

    这篇文章用几个简单的例子来介绍XCode6.1故事板中约束的使用方法.   现在iOS设备屏幕的尺寸也有很多种了,尤其是有了iPhone6 Plus以后,再不关注界面的尺寸适配就有点说不过去了.   ...

  5. CentOS 7 升级gcc/g++编译器

    gcc的升级必须要使用源码进行升级,也就说,必须要使用源码进行编译才行.我的7.2的CentOS目前自带的gcc是4.8.5的,gcc从4.8之后开始支持C++11,但是鉴于现在C++14.C++17 ...

  6. c++:printf和cout那个更好更快些

    现在群里在讨论cout和printf那个快的问题,但我个人觉得printf好: 因为:printf对于一些数据大,以及保留小数位,字符……可以显示出明显的优势如“%s %d %c…………” 虽然pri ...

  7. android-csv-variants

    android-csv-variants https://github.com/zawn/android-csv-variants/ 目的 用于在Android Gradle构建时通过CSV文件配置V ...

  8. WCF全局异常处理

    在用wcf做为单纯的服务端的时候,发生错误是常有的事情,特别是在调用其他系统提供的接口的时候,发生的一些错误总是让人摸不着头脑,严重影响了错误的定位.做.net web开发的时候,我们可以在Globa ...

  9. P2085 最小函数值 (堆)

    题目描述 有n个函数,分别为F1,F2,...,Fn.定义Fi(x)=Aix^2+Bix+Ci (x∈N*).给定这些Ai.Bi和Ci,请求出所有函数的所有函数值中最小的m个(如有重复的要输出多个). ...

  10. K-lord #2

    题目描述 还记得,高中数学联赛,2005,那道毒瘤题. 如果自然数的各位数字之和等于7,那么称为“吉祥数”.将所有“吉祥数”从小到大排成一列 $a_{1}$,$a_{2}$,$a_{3}$ ... , ...