题目链接 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. UVa 167(八皇后)、POJ2258 The Settlers of Catan——记两个简单回溯搜索

    UVa 167 题意:八行八列的棋盘每行每列都要有一个皇后,每个对角线上最多放一个皇后,让你放八个,使摆放位置上的数字加起来最大. 参考:https://blog.csdn.net/xiaoxiede ...

  2. C#图形学习笔记

    绘图常用控件.类和结构 颜色 使用System.Drawing.Color结构表示 设置颜色的方法 调用静态函数:Color.FromArgb() public static Color FromAr ...

  3. scrollTop如何实现click后页面过渡滚动到顶部

    用JS操作,body元素的scrollTop var getTop = document.getElementById("get-top"); var head = documen ...

  4. verilog RTL编程实践之四

    1.verilog平时三个级别: 1.gate level: and or not xor 2.RTL level: reg comb seq 3.behavior:+ – * / 2.system ...

  5. H.264编码profile & level控制

    背景知识 先科普一下profile&level.(这里讨论最常用的H264) H.264有四种画质级别,分别是baseline, extended, main, high:  1.Baseli ...

  6. 在oracle中怎么通过字段名查询其所在的表

    ora = //连接描述符名:ora (description = //描述 (address = //网络地址之一 (protocol = tcp) //网络协议(tcp表示TCP/IP协议) (h ...

  7. 关于在一台主机上安装2个不同版本的Oracle服务端

    一.安装Oracle12c 按正常安装方法安装即可! ORACLE_BASE=/u01/app ORACLE_HOME=/u01/app/oracle ORACLE_SID=a4orcl 二.安装Or ...

  8. C#简易日志输出

    精简版: public static void WriteLog(string message, string group = "") { var logPath = System ...

  9. 对于一棵二叉树,请设计一个算法,创建含有某一深度上所有结点的链表。 给定二叉树的根结点指针TreeNode* root,以及链表上结点的深度,请返回一个链表ListNode,代表该深度上所有结点的值,请按树上从左往右的顺序链接,保证深度不超过树的高度,树上结点的值为非负整数且不超过100000。

    /* struct TreeNode { int val; struct TreeNode *left; struct TreeNode *right; TreeNode(int x) : val(x ...

  10. EasyUI 动态更新列

    function UpdateRow() { var rows = $('#tbpmgridList').datagrid('getChecked'); var productid = ''; for ...