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
————————————————————————————
这道题我写的扫描线 
我们把一个询问(u->v)拆成四个 
设根为1 
询问的答案就是1->u + 1->v - 1->lca(u,v) 1-fa[lca] 
然后修改的影响范围只有这个点的子树 这个可以用dfs序+树状数组实现
然后我们每一种权值建一棵树(权值需要离散化) 当然因为如果每次都初始化树状数组肯定会T
这里我利用了时间戳  这样之后就解决问题了 就是代码可能有点复杂QAQ
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
const int M=1e6+,mod=;
int read(){
int ans=,f=,c=getchar();
while(c<''||c>''){if(c=='-') f=-; c=getchar();}
while(c>=''&&c<=''){ans=ans*+(c-''); c=getchar();}
return ans*f;
}
int n,m,k,v[M],l[M],r[M],pos[M];
int first[M],cnt,ans[M],mark[M];
struct node{int to,next;}e[*M];
void ins(int a,int b){e[++cnt]=(node){b,first[a]}; first[a]=cnt;}
void insert(int a,int b){ins(a,b); ins(b,a);}
int dep[M],f[M][],sum;
void dfs(int x){
l[x]=pos[x]=++sum;
for(int i=;(<<i)<=dep[x];i++) f[x][i]=f[f[x][i-]][i-];
for(int i=first[x];i;i=e[i].next){
int now=e[i].to;
if(!dep[now]){
dep[now]=dep[x]+;
f[now][]=x;
dfs(now);
}
}r[x]=sum;
}
int find(int x,int y){
if(dep[x]<dep[y]) std::swap(x,y);
int d=dep[x]-dep[y];
for(int i=;(<<i)<=d;i++) if(<<i&d) x=f[x][i];
if(x==y) return x;
for(int i=;i>=;i--)
if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
return f[x][];
}
struct P{int s,x,T;};
std::vector<P>e1[M];
struct Q{int l,r,T;};
std::vector<Q>e2[M];
int star[mod],cnth;
struct H{int to,next;}hash[M];
int get(int x){
int w=x%mod;
for(int i=star[w];i;i=hash[i].next) if(hash[i].to==x) return i;
cnth++; hash[cnth].to=x; hash[cnth].next=star[w]; star[w]=cnth;
return cnth;
}
char c[];
int s[M],now[M];
int lowbit(int x){return x&-x;}
void add(int x,int ss){
while(x<=n){
if(now[x]!=k) now[x]=k,s[x]=;
s[x]+=ss;
x+=lowbit(x);
}
}
int query(int x){
int ans=;
while(x){
if(now[x]==k) ans+=s[x];
x-=lowbit(x);
}
return ans;
}
int main(){
n=read(); m=read();
for(int i=;i<=n;i++){
v[i]=get(read());
e1[v[i]].push_back((P){,i,});
}
int x,y;
for(int i=;i<n;i++) x=read(),y=read(),insert(x,y);
dep[]=; dfs();
for(int i=;i<=m;i++){
scanf("%s",c);
if(c[]=='C'){
x=read(); k=get(read());
if(v[x]==k) continue;
e1[k].push_back((P){,x,i});
e1[v[x]].push_back((P){-,x,i});
v[x]=k;
}
else{
mark[i]=;
x=read(); y=read(); k=get(read());
e2[k].push_back((Q){x,y,i});
}
}
for(k=;k<=cnth;k++){
int now=;
P* h1=e1[k].data();
Q* h2=e2[k].data();
for(int i=;i<e2[k].size();i++){
while(now<e1[k].size()&&h1[now].T<=h2[i].T){
add(l[h1[now].x],h1[now].s);
add(r[h1[now].x]+,-h1[now].s);
now++;
}
int id=h2[i].T;
ans[id]+=query(pos[h2[i].l]); ans[id]+=query(pos[h2[i].r]);
int lca=find(h2[i].l,h2[i].r),fa=f[lca][];
ans[id]-=query(pos[lca]); ans[id]-=query(pos[fa]);
}
}
for(int i=;i<=m;i++)if(mark[i]) printf("%d\n",ans[i]);
return ;
}

bzoj 4999: This Problem Is Too Simple!的更多相关文章

  1. BZOJ 4999: This Problem Is Too Simple! DFS序+LCA+树状数组+离线

    Code: #include<bits/stdc++.h> #define setIO(s) freopen(s".in","r",stdin) , ...

  2. [BZOJ 4999]This Problem Is Too Simple!

    [BZOJ 4999]This Problem Is Too Simple! 题目 给您一颗树,每个节点有个初始值. 现在支持以下两种操作: 1. C i x(0<=x<2^31) 表示将 ...

  3. 4999: This Problem Is Too Simple!

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

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

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

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

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

  6. bzoj4999 This Problem Is Too Simple!

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

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

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

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

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

  9. 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 ...

随机推荐

  1. linux安装oracle远程客户端

    文章参考:http://blog.csdn.net/caomiao2006/article/details/11901123 感谢博友分享O(∩_∩)O~ 安装oracle 远程客户端(一般情况下本地 ...

  2. spring、spring-data-redis整合使用

    一.Redis是一个开源的使用ANSI C语言编写.支持网络.可基于内存亦可持久化的日志型.Key-Value数据库,并提供多种语言的API. 从2010年3月15日起,Redis的开发工作由VMwa ...

  3. html5判断设备的动作

    相应的事件 deviceorientation事件提供设备的物理方向信息,表示为一系列本地坐标系的旋角. devicemotion事件提供设备的加速信息,表示为定义在设备上的坐标系中的卡尔迪坐标.其还 ...

  4. 用Python 的一些用法与 JS 进行类比,看有什么相似?

    Python 是一门运用很广泛的语言,自动化脚本.爬虫,甚至在深度学习领域也都有 Python 的身影.作为一名前端开发者,也了解 ES6 中的很多特性借鉴自 Python (比如默认参数.解构赋值. ...

  5. Cassandra 在CQL中使用函数

    CQL 3.1 最后更新 2015年10月10日 maxTimeuuid() now() dateOf() minTimeuuid() --假设表结构如下 create table user ( us ...

  6. debian8.2安装kubernetes

    master上通过kubeadm安装Kubernetes 添加国内阿里源后安装kubeadm: deb https://mirrors.aliyun.com/kubernetes/apt/ kuber ...

  7. kaldi基于GMM的单音素模型 训练部分

    目录 1. gmm-init-mono 模型初始化 2. compile-train-graghs 训练图初始化 3. align-equal-compiled 特征文件均匀分割 4. gmm-acc ...

  8. SQL 基础笔记(三):约束

    个人笔记不保证正确. 数据类型是限制我们可以在表里存储什么数据的一种方法.不过,对于许多应用来说, 这种限制实在是太粗糙了.比如,一个包含产品价格的字段应该只接受正数. 但是没有哪种标准数据类型只接受 ...

  9. [leetcode-652-Find Duplicate Subtrees]

    Given a binary tree, return all duplicate subtrees. For each kind of duplicate subtrees, you only ne ...

  10. [leetcode-648-Replace Words]

    In English, we have a concept called root, which can be followed by some other words to form another ...