Description

S国有N个城市,编号从1到N。城市间用N-1条双向道路连接,满足
从一个城市出发可以到达其它所有城市。每个城市信仰不同的宗教,如飞天面条神教、隐形独角兽教、绝地教都是常见的信仰。为了方便,我们用不同的正整数代表各种宗教,  S国的居民常常旅行。旅行时他们总会走最短路,并且为了避免麻烦,只在信仰和他们相同的城市留宿。当然旅程的终点也是信仰与他相同的城市。S国政府为每个城市标定了不同的旅行评级,旅行者们常会记下途中(包括起点和终点)留宿过的城市的评级总和或最大值。
    在S国的历史上常会发生以下几种事件:
”CC x c”:城市x的居民全体改信了c教;
”CW x w”:城市x的评级调整为w;
”QS x y”:一位旅行者从城市x出发,到城市y,并记下了途中留宿过的城市的评级总和;
”QM x y”:一位旅行者从城市x出发,到城市y,并记下了途中留宿过
的城市的评级最大值。
    由于年代久远,旅行者记下的数字已经遗失了,但记录开始之前每座城市的信仰与评级,还有事件记录本身是完好的。请根据这些信息,还原旅行者记下的数字。    为了方便,我们认为事件之间的间隔足够长,以致在任意一次旅行中,所有城市的评级和信仰保持不变。

Input

输入的第一行包含整数N,Q依次表示城市数和事件数。
    接下来N行,第i+l行两个整数Wi,Ci依次表示记录开始之前,城市i的
评级和信仰。
    接下来N-1行每行两个整数x,y表示一条双向道路。
    接下来Q行,每行一个操作,格式如上所述。

Output

对每个QS和QM事件,输出一行,表示旅行者记下的数字。

题解:对于每一个宗教分别开一个线段树.

下标为树剖序,权值为树上点权.

由于宗教数目是 $O(n)$ 的,动态开点即可.

#include <bits/stdc++.h>
#define setIO(s) freopen(s".in","r",stdin)
#define ll long long
#define inf 100000000000
#define maxn 500000
#define N 200003
using namespace std;
namespace Seg
{
#define lson t[x].l
#define rson t[x].r
int n, tot;
struct Node
{
int l, r;
ll sumv, maxv;
}t[maxn << 2];
void pushup(int x)
{
t[x].sumv = t[lson].sumv + t[rson].sumv;
t[x].maxv = max(t[lson].maxv, t[rson].maxv);
}
void ins(int &x, int l, int r, int p, ll v)
{
if(!x) x = ++ tot;
if(l == r)
{
t[x].sumv = t[x].maxv = v;
return ;
}
int mid = (l + r) >> 1;
if(p <= mid) ins(lson, l, mid, p, v);
else ins(rson, mid + 1, r, p, v);
pushup(x);
}
void del(int x, int l, int r, int p)
{
if(l == r)
{
t[x].sumv = t[x].maxv = 0;
return ;
}
int mid = (l + r) >> 1;
if(p <= mid) del(lson, l, mid, p);
else del(rson, mid + 1, r, p);
pushup(x);
}
ll query_sum(int l, int r, int x, int L, int R)
{
if(!x) return 0;
if(l >= L && r <= R) return t[x].sumv;
ll tmp = 0;
int mid = (l + r) >> 1;
if(L <= mid) tmp += query_sum(l, mid, lson, L, R);
if(R > mid) tmp += query_sum(mid + 1, r, rson, L, R);
return tmp;
}
ll query_max(int l, int r, int x, int L, int R)
{
if(!x) return -inf;
if(l >= L && r <= R) return t[x].maxv;
ll tmp = -inf;
int mid = (l + r) >> 1;
if(L <= mid) tmp = max(tmp, query_max(l, mid, lson, L, R));
if(R > mid) tmp = max(tmp, query_max(mid + 1, r, rson, L, R));
return tmp;
}
#undef lson
#undef rson
};
char str[10];
int n, Q, edges, tim;
int hd[maxn], to[maxn << 1], nex[maxn << 1], W[maxn], C[maxn], fa[maxn], dep[maxn];
int ln[maxn], dfn[maxn], top[maxn], bot[maxn], siz[maxn], hson[maxn], rt[maxn];
void add(int u, int v)
{
nex[++edges] = hd[u], hd[u] = edges, to[edges] = v;
}
void dfs1(int u, int ff)
{
siz[u] = 1, fa[u] = ff, dep[u] = dep[ff] + 1;
for(int i = hd[u]; i ; i = nex[i])
{
int v = to[i];
if(v == ff) continue;
dfs1(v, u);
siz[u] += siz[v];
if(siz[hson[u]] < siz[v]) hson[u] = v;
}
}
void dfs2(int u, int tp)
{
top[u] = tp, ln[++tim] = u, dfn[u] = tim;
Seg :: ins(rt[C[u]], 1, N, tim, 1ll*W[u]);
if(hson[u])
dfs2(hson[u], tp), bot[u] = bot[hson[u]];
else
bot[u] = u;
for(int i = hd[u]; i ; i = nex[i])
{
int v = to[i];
if(v == fa[u] || v == hson[u]) continue;
dfs2(v, v);
}
}
ll _query_sum(int x, int y)
{
int ty = C[y];
ll tmp = 0;
// y is the deeper one
while(top[x] ^ top[y])
{
if(dep[top[x]] > dep[top[y]]) swap(x, y);
tmp += Seg :: query_sum(1, N, rt[ty], dfn[top[y]], dfn[y]);
y = fa[top[y]];
}
if(dep[x] > dep[y]) swap(x, y);
tmp += Seg :: query_sum(1, N, rt[ty], dfn[x], dfn[y]);
return tmp;
}
ll _query_max(int x, int y)
{
int ty = C[y];
ll tmp = 0;
while(top[x] ^ top[y])
{
if(dep[top[x]] > dep[top[y]]) swap(x, y);
tmp = max(tmp, Seg :: query_max(1, N, rt[ty], dfn[top[y]], dfn[y]));
y = fa[top[y]];
}
if(dep[x] > dep[y]) swap(x, y);
tmp = max(tmp, Seg :: query_max(1, N, rt[ty], dfn[x], dfn[y]));
return tmp;
}
int main()
{
// setIO("input");
scanf("%d%d",&n,&Q);
for(int i = 1;i <= n; ++i) scanf("%d%d",&W[i],&C[i]);
for(int i = 1, u, v; i < n; ++i)
{
scanf("%d%d",&u,&v), add(u, v), add(v, u);
}
Seg :: t[0].maxv = -inf;
dfs1(1, 0), dfs2(1, 1);
while(Q--)
{
scanf("%s",str);
int x, w, c, y;
if(str[1] == 'C')
{
scanf("%d%d",&x,&c);
Seg :: del(rt[C[x]], 1, N, dfn[x]);
C[x] = c;
Seg :: ins(rt[C[x]], 1, N, dfn[x], W[x]);
}
if(str[1] == 'W')
{
scanf("%d%d",&x,&w);
W[x] = w;
Seg :: ins(rt[C[x]], 1, N, dfn[x], 1ll*W[x]);
}
if(str[1] == 'S')
{
scanf("%d%d",&x,&y), printf("%lld\n",_query_sum(x, y));
}
if(str[1] == 'M')
{
scanf("%d%d",&x,&y), printf("%lld\n",_query_max(x, y));
}
}
return 0;
}

  

BZOJ 3531: [Sdoi2014]旅行 权值线段树 + 树链剖分的更多相关文章

  1. bzoj 3531 [Sdoi2014]旅行(树链剖分,线段树)

    3531: [Sdoi2014]旅行 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 876  Solved: 446[Submit][Status][ ...

  2. bzoj 3531 [Sdoi2014]旅行 (树剖+线段树 动态开点)

    3531: [Sdoi2014]旅行 Time Limit: 40 Sec  Memory Limit: 512 MBSubmit: 2984  Solved: 1312[Submit][Status ...

  3. BZOJ 3531: [Sdoi2014]旅行(树链剖分+线段树)

    传送门 解题思路 以每个颜色为根开一棵权值线段树,下标就是\(dfs\)序,其余都是基本操作,要动态开点. 代码 #include<iostream> #include<cstdio ...

  4. BZOJ 3531: [Sdoi2014]旅行 [树链剖分]

    3531: [Sdoi2014]旅行 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 1685  Solved: 751[Submit][Status] ...

  5. [bzoj 2733]启发式合并权值线段树

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2733 平衡树待学习.从一个博客学到了合并权值线段树的姿势:http://blog.csdn ...

  6. [bzoj 3531][SDOI2014]旅行(树链剖分+动态开点线段树)

    题目:http://www.lydsy.com:808/JudgeOnline/problem.php?id=3531 分析: 对于每个颜色(颜色<=10^5)都建立一颗线段树 什么!那么不是M ...

  7. BZOJ 3531 SDOI2014 旅行 树链剖分+线段树动态开点

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3531 题意概述: 给出一棵N个点的树,树上的每个结点有一个颜色和权值,支持以下四种操作: ...

  8. BZOJ 3531 [Sdoi2014]旅行 树链剖分+动态开点线段树

    题意 S国有N个城市,编号从1到N.城市间用N-1条双向道路连接,满足从一个城市出发可以到达其它所有城市.每个城市信仰不同的宗教,如飞天面条神教.隐形独角兽教.绝地教都是常见的信仰. 为了方便,我们用 ...

  9. bzoj 3531: [Sdoi2014]旅行

    Description S国有N个城市,编号从1到N.城市间用N-1条双向道路连接,满足从一个城市出发可以到达其它所有城市.每个城市信仰不同的宗教,如飞天面条神教.隐形独角兽教.绝地教都是常见的信仰. ...

随机推荐

  1. 洛谷—— P1379 八数码难题

    https://daniu.luogu.org/problem/show?pid=1379 题目描述 在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字.棋盘中留有一个空格,空格用0来表示 ...

  2. 记一次ruby的安装

    1,下载rubyinstall 安装包及devkit包 登陆网站 :http://rubyinstaller.org/downloads/ 安装rubyinstall包时添加到环境变量 2,安装完in ...

  3. MVC.Net:对MVC5部署时出现403.14错误的解决方法

    当我们部署MVC5到IIS 7的时候,有时会出现403.14的错误,如下图: 对于这个错误的解决方法就是在应用程序的web.config的system.webServer节点中加入这一句: <m ...

  4. AndroidUI组件之ActionBar

    有一段时间没有写博文了,发现自己的博文的完整度不是非常好.就拿AndroidUI组件这一块.一直没有更新完.我会尽快更新.好了.不多说了,今天来看一下ActionBar. 依照以往的作风.知识点都以代 ...

  5. 浅谈PHP数据结构之单链表

    什么是链表?(依据百度词条查询而得) 链表是一种物理存储单元上非连续.非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的.链表由一系列结点(链表中每个元素称为结点)组成,结点能够在执 ...

  6. luogu2467 [SDOI2010]地精部落

    题目大意 求在$[1,n]$的排列中是波动序列的数量. 题解 性质 当我们对波动序列$a$进行以下操作时,得到的新序列仍然是个波动序列: 若$a_i = a_j+1且|j-i|>1$,将$a_i ...

  7. [RK3288][Android6.0] U-boot 启动流程小结【转】

    本文转载自:http://blog.csdn.net/kris_fei/article/details/52536093 Platform: RK3288OS: Android 6.0Version: ...

  8. C#中数据库备份还原 精简

    C#中数据库备份还原 使用前要导入SQLDMO.dll(在com组件中导入Microsoft SQLDMO Object Library即可) ///     /// DbOper类,主要应用SQLD ...

  9. CentOS7 内核参数优化

    # allow testing with buffers up to 128MBnet.core.rmem_max = 134217728net.core.wmem_max = 134217728# ...

  10. 关于offer对比

    前天签了三方,在签约前的几个小时,还在纠结到底该accept哪个offer,相信很多同学都会遇到这个问题,就由此展开去吧. 关于offer的选择,无外乎以下几个考察点:1.个人发展:2.地域:3.薪资 ...