BZOJ2243
来源:互联网 发布:高性能网络编程1 编辑:程序博客网 时间:2024/05/29 16:46
给定一棵有n个节点的无根树和m个操作,操作有2类:
1、将节点a到节点b路径上所有点都染成颜色c;
2、询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“ 112221 ” 由3段组成:“ 11 ” 、“ 222 ” 和“ 1 ” 。
请你写一个程序依次完成这m个操作。
Input
第一行包含2个整数n和m,分别表示节点数和操作数;
第二行包含n个正整数表示n个节点的初始颜色
下面 行每行包含两个整数x和y,表示x和y之间有一条无向边。
下面 行每行描述一个操作:
“C a b c”表示这是一个染色操作,把节点a到节点b路径上所有点(包括a和b)都染成颜色c;
“Q a b”表示这是一个询问操作,询问节点a到节点b(包括a和b)路径上的颜色段数量。
Output
对于每个询问操作,输出一行答案。
Sample Input
6 5
2 2 1 2 1 1
1 2
1 3
2 4
2 5
2 6
Q 3 5
C 2 1 1
Q 3 5
C 5 1 2
Q 3 5
Sample Output
3
1
2
Hint
数N<=10^5,操作数M<=10^5,所有的颜色C为整数且在[0, 10^9]之间。
思路:
1,这道题主要是对于线段树的查询操作,在查询的时候,如果被查询的区间被分成了两半,那么我们还需判断分割点处的颜色是否相同,相同就要减一。
2,其次在重链中往上跳的时候还要判断跳的两端点(也就是t1以及t1的父节点)的颜色是否一样。
#include <bits/stdc++.h>using namespace std;#define lson l,m,rt<<1#define rson m+1,r,rt<<1|1const int maxn=1e5+9;int sz[maxn],fa[maxn],tp[maxn],son[maxn],dep[maxn],id[maxn],idx,fx[maxn],color[maxn];int tag[maxn<<2],sum[maxn<<2],ls[maxn<<2],rs[maxn<<2];int n,m;vector<int> mp[maxn];void dfs1(int u,int f,int d){ son[u]=0,sz[u]=1,fa[u]=f,dep[u]=d; for(int i=0; i<mp[u].size(); i++) { int v=mp[u][i]; if(v==fa[u]) continue; dfs1(v,u,d+1); sz[u]+=sz[v]; if(son[u]==0||sz[son[u]]<sz[v]) son[u]=v; }}void dfs2(int u,int tpp){ tp[u]=tpp; id[u]=++idx; fx[idx]=u; if(son[u])dfs2(son[u],tpp); for(int i=0; i<mp[u].size(); i++) { int v=mp[u][i]; if(v==fa[u]||v==son[u]) continue; dfs2(v,v); }}void pushdown(int rt){ if(tag[rt]!=-1) { tag[rt<<1]=tag[rt<<1|1]=tag[rt]; ls[rt<<1]=ls[rt<<1|1]=rs[rt<<1]=rs[rt<<1|1]=tag[rt]; tag[rt]=-1; sum[rt<<1]=sum[rt<<1|1]=1; }}void pushup(int rt){ sum[rt]=sum[rt<<1]+sum[rt<<1|1]; if(rs[rt<<1]==ls[rt<<1|1]) sum[rt]--; ls[rt]=ls[rt<<1];//由于我的初始化的方式这里必须这样写 rs[rt]=rs[rt<<1|1];//否则,对于build以后的建树是有问题的}void build(int l,int r,int rt){ tag[rt]=-1; if(l==r) { ls[rt]=rs[rt]=color[fx[l]]; sum[rt]=1; return; } int m=l+r>>1; build(lson); build(rson); pushup(rt);}void update(int L,int R,int c,int l,int r,int rt){ if(L<=l&&r<=R) { tag[rt]=c; ls[rt]=rs[rt]=c; sum[rt]=1; return; } if(tag[rt]==c) return; pushdown(rt); int m=l+r>>1; if(L<=m) update(L,R,c,lson); if(m<R) update(L,R,c,rson); pushup(rt);}int query(int L,int R,int l,int r,int rt){ if(L==l&&r==R||tag[rt]!=-1) return sum[rt]; pushdown(rt); int m=l+r>>1; if(m<L) return query(L,R,rson); else if(R<=m) return query(L,R,lson); else { int ret=query(L,m,lson)+query(m+1,R,rson); if(rs[rt<<1]==ls[rt<<1|1]) ret--;//判断分割点处的颜色分配情况 return ret; }}int qp(int p,int l,int r,int rt)//查询改变后的颜色{ if(l==r) return ls[rt]; int m=l+r>>1; pushdown(rt); if(p<=m) return qp(p,lson); else return qp(p,rson);}int qq(int l,int r,int op){ int sum=0; int t1=tp[l],t2=tp[r]; while(t2!=t1) { if(dep[t1]<dep[t2]) { swap(t1,t2); swap(l,r); } if(op!=-1) update(id[t1],id[l],op,1,idx,1); else { sum+=query(id[t1],id[l],1,idx,1); if(qp(id[fa[t1]],1,idx,1)==qp(id[t1],1,idx,1)) sum--;//处理跳跃点出的情况,这里画图可知,是不可能跳出去的 } l=fa[t1]; t1=tp[l]; } if(dep[l]>dep[r]) swap(l,r); if(op!=-1) { update(id[l],id[r],op,1,idx,1); return -1; } else { sum+=query(id[l],id[r],1,idx,1); return sum; }}int main(){ scanf("%d%d",&n,&m); for(int i=1; i<=n; i++) scanf("%d",&color[i]); for(int i=1; i<n; i++) { int u,v; scanf("%d%d",&u,&v); mp[u].push_back(v); mp[v].push_back(u); } dfs1(1,-1,1); dfs2(1,1); build(1,idx,1); while(m--) { char op[3]; scanf("%s",op); int a,b,c; scanf("%d%d",&a,&b); if(op[0]=='Q') { printf("%d\n",qq(a,b,-1)); } else { scanf("%d",&c); qq(a,b,c); } } return 0;}
阅读全文
0 0
- BZOJ2243
- BZOJ2243 树链剖分
- 树链剖分(bzoj2243)
- BZOJ2243 染色
- 【Bzoj2243】染色
- bzoj2243 mode
- bzoj2243染色
- bzoj2243 树链剖分
- [Bzoj2243][SDOI2011]染色
- bzoj2243: [SDOI2011]染色 树链剖分
- 【BZOJ2243】[SDOI2011]染色 树链剖分
- 【BZOJ2243】【SDOI2011】染色 树链剖分
- 【SDOI2011】【BZOJ2243】【树链剖分】染色
- 【bzoj2243】【sdoi2011】染色【树链剖分】
- bzoj2243: [SDOI2011]染色
- [BZOJ2243][SDOI2011]染色
- 【bzoj2243】 [SDOI2011]染色
- bzoj2243: [SDOI2011]染色
- linux IPC---共享内存
- Java集合---HashSet的源码分析
- 使用Eclipse从SVN检出Maven项目
- Android多点触控实现图片缩放预览
- socket网络协议
- BZOJ2243
- Java集合---ConcurrentHashMap原理
- 删除表中重复数据
- maven 笔记
- list去重
- ZOJ 3537-Cake(凸包+最优三角刨分+区间DP)
- 泛型
- Sentence-LDA的介绍及程序
- Java类加载器原理解析