Description

给您一颗树,每个节点有个初始值。
现在支持以下两种操作:
1. C i x(0<=x<2^31) 表示将i节点的值改为x。
2. Q i j x(0<=x<2^31) 表示询问i节点到j节点的路径上有多少个值为x的节点。

Input

第一行有两个整数N,Q(1 ≤N≤ 100,000;1 ≤Q≤ 200,000),分别表示节点个数和操作个数。
下面一行N个整数,表示初始时每个节点的初始值。
接下来N-1行,每行两个整数x,y,表示x节点与y节点之间有边直接相连(描述一颗树)。
接下来Q行,每行表示一个操作,操作的描述已经在题目描述中给出。

Output

对于每个Q输出单独一行表示所求的答案。

Sample Input

5 6
10 20 30 40 50
1 2
1 3
3 4
3 5
Q 2 3 40
C 1 40
Q 2 3 40
Q 4 5 30
C 3 10
Q 4 5 30

Sample Output

0
1
1
0

正解:树链剖分+线段树。

傻逼题,直接对于每一个权值建一棵线段树,然后树剖扣路径即可。

 #include <bits/stdc++.h>
#define il inline
#define RG register
#define ll long long
#define lb(x) (x & -x)
#define N (300010) using namespace std; struct edge{ int nt,to; }g[N<<];
struct data{ int op,x,y,v; }q[N]; int head[N],top[N],fa[N],son[N],dfn[N],dep[N],sz[N],n,num,cnt;
int sum[*N],ls[*N],rs[*N],rt[N],hsh[N],a[N],tot,Sz,Q;
char ch[]; il int gi(){
RG int x=,q=; RG char ch=getchar();
while ((ch<'' || ch>'') && ch!='-') ch=getchar();
if (ch=='-') q=-,ch=getchar();
while (ch>='' && ch<='') x=x*+ch-,ch=getchar();
return q*x;
} il void insert(RG int from,RG int to){
g[++num]=(edge){head[from],to},head[from]=num; return;
} il void dfs1(RG int x,RG int p){
fa[x]=p,dep[x]=dep[p]+,sz[x]=; RG int v;
for (RG int i=head[x];i;i=g[i].nt){
v=g[i].to; if (v==p) continue;
dfs1(v,x),sz[x]+=sz[v];
if (sz[son[x]]<=sz[v]) son[x]=v;
}
return;
} il void dfs2(RG int x,RG int p,RG int anc){
top[x]=anc,dfn[x]=++cnt; RG int v;
if (son[x]) dfs2(son[x],x,anc);
for (RG int i=head[x];i;i=g[i].nt){
v=g[i].to; if (v==p || v==son[x]) continue;
dfs2(v,x,v);
}
return;
} il void update(RG int &x,RG int l,RG int r,RG int p,RG int v){
if (!x) x=++Sz; if (l==r){ sum[x]+=v; return; } RG int mid=(l+r)>>;
p<=mid ? update(ls[x],l,mid,p,v) : update(rs[x],mid+,r,p,v);
sum[x]=sum[ls[x]]+sum[rs[x]]; return;
} il int query(RG int x,RG int l,RG int r,RG int xl,RG int xr){
if (xl<=l && r<=xr) return sum[x]; RG int mid=(l+r)>>;
if (xr<=mid) return query(ls[x],l,mid,xl,xr);
else if (xl>mid) return query(rs[x],mid+,r,xl,xr);
else return query(ls[x],l,mid,xl,mid)+query(rs[x],mid+,r,mid+,xr);
} il int Query(RG int u,RG int v,RG int k){
RG int ans=;
while (top[u]!=top[v]){
if (dep[top[u]]<dep[top[v]]) swap(u,v);
ans+=query(rt[k],,n,dfn[top[u]],dfn[u]),u=fa[top[u]];
}
if (dep[u]>dep[v]) swap(u,v);
ans+=query(rt[k],,n,dfn[u],dfn[v]); return ans;
} int main(){
#ifndef ONLINE_JUDGE
freopen("simple.in","r",stdin);
freopen("simple.out","w",stdout);
#endif
n=gi(),Q=gi();
for (RG int i=;i<=n;++i) a[i]=gi(),hsh[++tot]=a[i];
for (RG int i=,x,y;i<n;++i) x=gi(),y=gi(),insert(x,y),insert(y,x);
dfs1(,),dfs2(,,);
for (RG int i=;i<=Q;++i){
scanf("%s",ch);
if (ch[]=='C') q[i].op=,q[i].x=gi(); else q[i].x=gi(),q[i].y=gi();
q[i].v=gi(),hsh[++tot]=q[i].v;
}
sort(hsh+,hsh+tot+),tot=unique(hsh+,hsh+tot+)-hsh-;
for (RG int i=;i<=n;++i) a[i]=lower_bound(hsh+,hsh+tot+,a[i])-hsh,update(rt[a[i]],,n,dfn[i],);
for (RG int i=;i<=Q;++i){
q[i].v=lower_bound(hsh+,hsh+tot+,q[i].v)-hsh;
if (q[i].op) update(rt[a[q[i].x]],,n,dfn[q[i].x],-),update(rt[a[q[i].x]=q[i].v],,n,dfn[q[i].x],);
else printf("%d\n",Query(q[i].x,q[i].y,q[i].v));
}
return ;
}

bzoj4999 This Problem Is Too Simple!的更多相关文章

  1. 2019.03.09 bzoj4999: This Problem Is Too Simple!(树链剖分+线段树动态开点)

    传送门 题意:给一颗树,每个节点有个初始值,要求支持将i节点的值改为x或询问i节点到j节点的路径上有多少个值为x的节点. 思路: 考虑对每种颜色动态开点,然后用树剖+线段树维护就完了. 代码: #in ...

  2. BZOJ4999: This Problem Is Too Simple!树链剖分+动态开点线段树

    题目大意:将某个节点的颜色变为x,查询i,j路径上多少个颜色为x的点... 其实最开始一看就是主席树+树状数组+DFS序...但是过不去...MLE+TLE BY FCWWW 其实树剖裸的一批...只 ...

  3. 【BZOJ4999】This Problem Is Too Simple!(线段树)

    [BZOJ4999]This Problem Is Too Simple!(线段树) 题面 BZOJ 题解 对于每个值,维护一棵线段树就好啦 动态开点,否则空间开不下 剩下的就是很简单的问题啦 当然了 ...

  4. 【BZOJ4999】This Problem Is Too Simple! 离线+树状数组+LCA

    [BZOJ4999]This Problem Is Too Simple! Description 给您一颗树,每个节点有个初始值. 现在支持以下两种操作: 1. C i x(0<=x<2 ...

  5. BZOJ4999:This Problem Is Too Simple!(DFS序&树上差分&线段树动态开点:区间修改单点查询)

    Description 给您一颗树,每个节点有个初始值. 现在支持以下两种操作: 1. C i x(0<=x<2^31) 表示将i节点的值改为x. 2. Q i j x(0<=x&l ...

  6. 【bzoj4999】This Problem Is Too Simple! 树链剖分+动态开点线段树

    题目描述 给您一颗树,每个节点有个初始值. 现在支持以下两种操作: 1. C i x(0<=x<2^31) 表示将i节点的值改为x. 2. Q i j x(0<=x<2^31) ...

  7. BZOJ4999 This Problem Is Too Simple!(树上差分+dfs序+树状数组)

    对每个权值分别考虑.则只有单点加路径求和的操作.树上差分转化为求到根的路径和,子树加即可.再差分后bit即可.注意树上差分中根的父亲是0,已经忘了是第几次因为这个挂了. #include<ios ...

  8. 4999: This Problem Is Too Simple!

    Description 给您一颗树,每个节点有个初始值. 现在支持以下两种操作: C i x(0<=x<2^31) 表示将i节点的值改为x. Q i j x(0<=x<2^31 ...

  9. bzoj 4999: This Problem Is Too Simple!

    Description 给您一颗树,每个节点有个初始值. 现在支持以下两种操作: 1. C i x(0<=x<2^31) 表示将i节点的值改为x. 2. Q i j x(0<=x&l ...

随机推荐

  1. qs.parse() 和 qs.stringfy() 之 传输数据秘籍

    qs是一个npm仓库所管理的包,可通过npm install qs命令进行安装. 1. qs.parse()将URL解析成对象的形式 const Qs = require('qs');let url ...

  2. C# MODBUS 通信

    背景 电厂有多组监控设备,需要在指定的设备上显示某些数据(其他设备对接过来的).通信协议是modbus主从结构. 源码: http://download.csdn.net/download/wolf1 ...

  3. MongoDB数据库进阶 --- 增删查改...

    注意: monogdb数据在使用之后必须及时 mongodb.close()否则后台崩溃. 在之前的文章中,我已经介绍了什么事MongoDB以及怎么在windows下安装MongoDB等等基本知识. ...

  4. jquery 属性选择器

    jquery 属性选择器   第一种根据属性选择E[attr] $("[title]").click().......... 即选择所有元素内 属性带有title的元素即<l ...

  5. opensuse13.2国内源和设置命令

    ustc-osshttp://mirrors.ustc.edu.cn/opensuse/distribution/13.2/repo/oss/ustc-non-osshttp://mirrors.us ...

  6. TOJ 2926 Series

    Description An arithmetic series consists of a sequence of terms such that each term minus its immed ...

  7. 给python解释器本身添加注册表

    import sys from _winreg import * # tweak as necessary version = sys.version[:3] installpath = sys.pr ...

  8. etcd单机集群

    etcd在单机部署集群,可以先弄清楚配置文件参数的意思.起3个集成监听不同的端口号 1. 启动 在/etc/soft/etcd/node1文件夹中,创建脚本start1.sh etcd --name ...

  9. Dozer 实现对象间属性复制

    使用场景:两个领域之间对象转换. 比如:在系统分层解耦过程中, 对外facade接口,一般使用VO对象,而内core业务逻辑层或者数据层通常使用Entity实体. VO对象 package com.m ...

  10. jq实现发送验证码倒计时60s

    setInterval() :按照指定的周期(以毫秒计)来调用函数或计算表达式.方法会不停地调用函数,直到 clearInterval() 被调用或窗口被关闭. setTimeout() :在指定的毫 ...