BZOJ 2243 [SDOI2011]染色 树链剖分+LCA+区间合并线段树
来源:互联网 发布:2017网络安全法答案 编辑:程序博客网 时间:2024/05/20 11:27
题意:
给定一棵有n个节点的无根树和m个操作,操作有2类:
1、将节点a到节点b路径上所有点都染成颜色c;
2、询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由3段组成:“11”、“222”和“1”。
请你写一个程序依次完成这m个操作。
思路:
这道题敲了很久…..(好恶心….
但是AC了真的很exciting
就是要考虑到区间合并,两条链进行合并的时候要判断
ft[x][i]就是从x节点向上跳2^i次方个节点所到达的节点
就是运用倍增的思想…倍增思想的请看郭大侠的讲解http://www.bilibili.com/video/av4419432/
这道题有两个操作
1、将节点a到节点b路径上所有点都染成颜色c 这个很简单,就是正常的树剖+线段树+lazy就OK了
还有LCA有点麻烦
下一个
2、询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由3段组成:“11”、“222”和“1”。这里需要+区间合并
我们先剖分整棵树,注意再剖分的过程中进行倍增的预处理,因为我们要求LCA
然后线段树query拆分区间的时候要注意一下
每次查询和插入的时候我们通过把区间分为[L,LCA] and [LCA,R]来处理
这么想想….好像是水题QAQ
就是区间合并和求LCA的时候注意一下就行了
#include<stdio.h>#include<string.h>#include<iostream>#include<algorithm>#include<math.h>#include<queue>#include<stack>#include<string>#include<vector>#include<map>#include<set>using namespace std;#define lowbit(x) (x&(-x))typedef long long LL;#define maxn 200005const int inf=(1<<28)-1;int A[maxn];struct node{ int next,to;}e[maxn*2];int h[maxn],tot;void add_edge(int a,int b){ e[++tot].next=h[a]; e[tot].to=b; h[a]=tot;}//Graph*******************************int ft[maxn][18];int son[maxn],fa[maxn],siz[maxn],deep[maxn];//求重儿子 父亲节点 节点子树大小 深度 和倍增节点 void dfs1(int u,int pre,int dep){ deep[u]=dep;fa[u]=pre; siz[u]=1; for(int i=1;i<=17;++i) { if(deep[u]<(1<<i)) break; ft[u][i]=ft[ft[u][i-1]][i-1]; } for(int i=h[u];~i;i=e[i].next) { int v=e[i].to; if(v!=pre) { ft[v][0]=u; dfs1(v,u,dep+1); siz[u]+=siz[v]; if(son[u]==-1||siz[son[u]]<siz[v]) son[u]=v; } }}int tid[maxn],Rank[maxn],top[maxn];int tim;//给节点标号和求top节点void dfs2(int u,int tp){ top[u]=tp; tid[u]=++tim; Rank[tim]=u; if(son[u]==-1) return ; dfs2(son[u],tp); for(int i=h[u];~i;i=e[i].next) { int v=e[i].to; if(v!=fa[u]&&v!=son[u]) dfs2(v,v); }}int lca(int x,int y){ if(deep[x]<deep[y]) swap(x,y); int t=deep[x]-deep[y]; for(int i=0;i<18;++i) if(t&(1<<i)) x=ft[x][i]; for(int i=17;i>=0;--i) if(ft[x][i]!=ft[y][i]) { x=ft[x][i]; y=ft[y][i]; } if(x==y) return x; return ft[x][0];}//树剖********************************* struct Segment{ int lc,rc,sum,lazy;}tree[maxn*4];void Push_up(int rt){ tree[rt].lc=tree[rt*2].lc; tree[rt].rc=tree[rt*2+1].rc; tree[rt].sum=tree[rt*2].sum+tree[rt*2+1].sum; if(tree[rt*2].rc==tree[rt*2+1].lc) tree[rt].sum--;}void Copy(int rt1,int rt){ tree[rt1].lc=tree[rt].lazy; tree[rt1].rc=tree[rt].lazy; tree[rt1].lazy=tree[rt].lazy; tree[rt1].sum=1;}void Push_down(int rt){ if(tree[rt].lazy==-1) return ; Copy(rt*2,rt); Copy(rt*2+1,rt); tree[rt].lazy=-1;}void build(int l,int r,int rt){ tree[rt].lazy=-1; if(l==r) { tree[rt].lc=tree[rt].rc=A[Rank[l]]; tree[rt].sum=1; return ; } int mid=(l+r)/2; build(l,mid,rt*2); build(mid+1,r,rt*2+1); Push_up(rt);}void Insert(int left,int right,int l,int r,int rt,int c){ if(left<=l&&r<=right) { tree[rt].lc=tree[rt].rc=c; tree[rt].sum=1;tree[rt].lazy=c; return ; } Push_down(rt); int mid=(l+r)/2; if(left<=mid) Insert(left,right,l,mid,rt*2,c); if(right>mid) Insert(left,right,mid+1,r,rt*2+1,c); Push_up(rt);}int query(int left,int right,int l,int r,int rt){ if(left<=l&&r<=right) return tree[rt].sum; Push_down(rt); int mid=(l+r)/2; int tmp=0; if(left>mid) tmp=query(left,right,mid+1,r,rt*2+1); else if(right<=mid) tmp=query(left,right,l,mid,rt*2); else { tmp=query(left,right,l,mid,rt*2); tmp+=query(left,right,mid+1,r,rt*2+1); if(tree[rt*2].rc==tree[rt*2+1].lc) tmp--; } Push_up(rt); return tmp;}int find(int pos,int l,int r,int rt){ if(l==r) return tree[rt].lc; Push_down(rt); int mid=(l+r)/2,tmp; if(pos>mid) return find(pos,mid+1,r,rt*2+1); else return find(pos,l,mid,rt*2); Push_up(rt); return tmp;}//Segment*********************************void init(){ tot=0,tim=0; memset(h,-1,sizeof(h)); memset(son,-1,sizeof(son));}int n;void Change(int x,int t,int c){ while(top[x]!=top[t]) { Insert(tid[top[x]],tid[x],1,n,1,c); x=fa[top[x]]; } Insert(tid[t],tid[x],1,n,1,c);}int Solve(int x,int t){ int res=0; while(top[x]!=top[t]) { res+=query(tid[top[x]],tid[x],1,n,1); if(find(tid[top[x]],1,n,1)==find(tid[ft[top[x]][0]],1,n,1)) res--; x=fa[top[x]]; } res+=query(tid[t],tid[x],1,n,1); return res;}int main(){ init(); int m; scanf("%d%d",&n,&m); for(int i=1;i<=n;++i) scanf("%d",&A[i]); for(int i=1;i<n;++i) { int u,v; scanf("%d%d",&u,&v); add_edge(u,v); add_edge(v,u); } dfs1(1,0,0); dfs2(1,1); build(1,n,1); for(int i=1;i<=m;++i) { char str[5]; scanf("%s",str); if(str[0]=='C') { int u,v,c; scanf("%d%d%d",&u,&v,&c); int t=lca(u,v); Change(u,t,c); Change(v,t,c); } else { int u,v; scanf("%d%d",&u,&v); int t=lca(u,v); printf("%d\n",Solve(u,t)+Solve(v,t)-1); } } return 0;}
0 0
- BZOJ 2243 [SDOI2011]染色 树链剖分+LCA+区间合并线段树
- BZOJ 2243: [SDOI2011]染色 树链剖分 区间合并
- bzoj 2243: [SDOI2011]染色 树链剖分+线段树
- Bzoj 2243: [SDOI2011]染色(树链剖分+线段树)
- BZOJ 2243: [SDOI2011]染色 树链剖分+线段树
- BZOJ 2243 染色(树链剖分+线段树区间合并)
- BZOJ-2243: [SDOI2011]染色 (树链剖分 入门题 线段树 区间修改查询 维护端点值)
- bzoj 2243 [SDOI2011]染色 树链剖分区间更新
- bzoj 2243 [SDOI2011]染色 树剖+线段树
- BZOJ 2243: [SDOI2011]染色 (树链剖分,点权,线段树)
- bzoj 2243: [SDOI2011]染色 (树链剖分+线段树)
- bzoj 2243 [SDOI2011]染色 (线段树 + 树链剖分)
- 【bzoj2243】[SDOI2011]染色 树链剖分 (区间合并处理)
- Bzoj-2243 [SDOI2011]染色(动态树/树链剖分)
- 【BZOJ】2243 [SDOI2011]染色 树链剖分
- BZOJ 2243 SDOI2011 染色 树链剖分
- BZOJ 2243 [SDOI2011] 染色 (树链剖分)
- BZOJ 2243: [SDOI2011]染色 【树链剖分】
- 获取网络图片+ViewPager+自动轮播
- 二维数组查找
- IOS函数可变参数
- [5-15] 打好基础,不忘初心
- 最速下降法
- BZOJ 2243 [SDOI2011]染色 树链剖分+LCA+区间合并线段树
- java 虚拟机之 boolean 类型
- React学习笔记—组件复用
- PLSQL练习
- Gym 100712G Heavy Coins
- 饿汉单例设计模式
- 跟着郝斌学数据结构(07)——队列(操作及应用)
- 子序列的和(subsequence)
- 机器学习算法一览表附opencv机器学习模块