BZOJ 2243 浅谈树链剖分+线段树
来源:互联网 发布:vue.js 实现网页下载 编辑:程序博客网 时间:2024/06/04 00:48
世界真的很大
前几次考试有一次树链剖分当场写挂之后调了一下午
一直耿耿于怀,于是乎找一道树链剖分的题来练手
虽然代码量略大但是调试起来还是比较轻松,一个小错误卡了一会儿
没搞明白root根本没有赋值为什么还能过样例
一直RE加上return就A了
看题先:
description:
给定一棵有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:
对于每个询问操作,输出一行答案。
树上链修改和查询,1e5的数据范围,应该能想到树链剖分
树链剖分的目的主要是为了那个特殊的DFS序,不光满足子树的DFS序是连续的一段,还满足一条重链上的点的dfs序是连续的一段
重链就是指子树最大的子节点所组成的链
这样就把“树”这么一个图抽象成了序列,然后就可以用数据结构维护序列的信息,然后通过序列与树的关系来得到答案
树上的链可以由一条条重链的一部分拆分得到,而重链由在DFS序上是连续的一段,所以可以用线段树来维护。
由于一条链最多被拆分成log条重链,而一次线段树查询时log的,那么一次链询问就是log^2的,总复杂度就是mlog^2的
这道题我们求的是链上有多少颜色段,那么线段树的一个区间就保存颜色段的数量,由于树上链会被拆分,于是乎会多次查询线段,有可能两条线段拼起来会形成一段颜色,这样就会重复计数。所以想到再记录一下每个线段两个端点的颜色,如果上一条线段的做断电与这一条线段的右端点相等的话,ans就–
还有染色操作,就是区间覆盖,搞一个标记flag,在查询时注意pushdown就行了,还是比较好写
完整代码:
#include<stdio.h>#include<algorithm>using namespace std;struct edge{ int v,last;}ed[400010];struct node{ int sum,lc,rc,flag; node *ls,*rs; void pushdown() { if(flag) { ls->sum=rs->sum=1; ls->flag=rs->flag=flag; ls->lc=ls->rc=lc; rs->lc=rs->rc=lc; flag=0; } } void update() { sum=ls->sum+rs->sum-(ls->rc == rs->lc); lc=ls->lc,rc=rs->rc; }}pool[4000010],*tail=pool,*root;int n,m,num=0,idx=0;int head[400010],a[400010],rev[400010],in[400010],dep[400010];int siz[400010],top[400010],son[400010],fa[400010];void add(int u,int v){ num++; ed[num].v=v; ed[num].last=head[u]; head[u]=num;}void dfs1(int u){ siz[u]=1; for(int i=head[u];i;i=ed[i].last) { int v=ed[i].v; if(v==fa[u]) continue ; dep[v]=dep[u]+1,fa[v]=u; dfs1(v); siz[u]+=siz[v]; if(siz[son[u]]<siz[v]) son[u]=v; }}void dfs2(int u,int tp){ in[u]=++idx; top[u]=tp,rev[idx]=u; if(son[u]) dfs2(son[u],tp); for(int i=head[u];i;i=ed[i].last) { int v=ed[i].v; if(v==fa[u] || v==son[u]) continue ; dfs2(v,v); }}node *build(int lf,int rg){ node *nd=++tail; if(lf==rg) { nd->sum=1,nd->flag=0; nd->lc=nd->rc=a[rev[lf]]; nd->ls=nd->rs=0; return nd; } int mid=(lf+rg)>>1; nd->flag=0; nd->ls=build(lf,mid); nd->rs=build(mid+1,rg); nd->update(); return nd;}void modify(node *nd,int lf,int rg,int L,int R,int delta){ if(L<=lf && rg<=R) { nd->sum=1,nd->lc=nd->rc=delta; nd->flag=delta; return ; } nd->pushdown(); int mid=(lf+rg)>>1; if(L<=mid) modify(nd->ls,lf,mid,L,R,delta); if(R>mid) modify(nd->rs,mid+1,rg,L,R,delta); nd->update();}void modify(int u,int v,int delta){ while(top[u]!=top[v]) { if(dep[top[u]] < dep[top[v]]) swap(u,v); modify(root,1,idx,in[top[u]],in[u],delta); u=fa[top[u]]; } if(dep[u]<dep[v]) swap(u,v); modify(root,1,idx,in[v],in[u],delta);}int query(node *nd,int lf,int rg,int L,int R,int &lns,int &rns){ if(lf==L) lns=nd->lc; if(rg==R) rns=nd->rc; if(L<=lf && rg<=R) return nd->sum; nd->pushdown(); int mid=(lf+rg)>>1,rt=-1,lt=-1; if(L<=mid) lt=query(nd->ls,lf,mid,L,R,lns,rns); if(R>mid) rt=query(nd->rs,mid+1,rg,L,R,lns,rns); if(lt<0) return rt; if(rt<0) return lt; return lt+rt-(nd->ls->rc==nd->rs->lc);}int query(int u,int v){ int ans=0,L,R,lf=-1,rg=-1; while(top[u]!=top[v]) { if(dep[top[u]] < dep[top[v]]) swap(u,v),swap(lf,rg); ans+=query(root,1,idx,in[top[u]],in[u],L,R); if(R==lf) ans--; lf=L,u=fa[top[u]]; } if(dep[u]<dep[v]) swap(u,v),swap(lf,rg); ans+=query(root,1,idx,in[v],in[u],L,R); if(R==lf) ans--; if(L==rg) ans--; return ans;}int main(){ 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(u,v),add(v,u); } dfs1(1); dfs2(1,1); root=build(1,idx); while(m--) { char ss[10]; int u,v,cor; scanf("%s",ss); if(ss[0]=='C') { scanf("%d%d%d",&u,&v,&cor); modify(u,v,cor); } else { scanf("%d%d",&u,&v); printf("%d\n",query(u,v)); } } return 0;}/*Whoso pulleth out this sword from this stone and anvil is duly born King of all England*/
嗯,就是这样
- BZOJ 2243 浅谈树链剖分+线段树
- BZOJ 4034浅谈树链剖分及线段树维护
- BZOJ 2243 树链剖分+线段树
- BZOJ 2243 染色(树链剖分+线段树)
- 【BZOJ 2243】染色 - 树链剖分+线段树
- bzoj 2243: [SDOI2011]染色 树链剖分+线段树
- Bzoj 2243: [SDOI2011]染色(树链剖分+线段树)
- BZOJ 2243(树链剖分+线段树 解法)
- BZOJ 2243: [SDOI2011]染色 树链剖分+线段树
- [BZOJ]2243 染色 树链剖分+线段树
- BZOJ 2243 染色 线段树+树链剖分
- bzoj 1984(线段树+树链剖分)
- BZOJ 4034 树链剖分 + 线段树
- BZOJ 2836 树链剖分+线段树
- BZOJ 2243 染色(树链剖分+线段树区间合并)
- BZOJ 2243 染色(树链剖分+线段树区间更新)
- BZOJ 2243 [SDOI2011]染色 树链剖分+LCA+区间合并线段树
- BZOJ 2243: [SDOI2011]染色 (树链剖分,点权,线段树)
- spring mvc入门
- 笔记:一键分享插件
- 【算法】找零钱-动态规划实现过程解析
- python __name__ = '__main__'的作用
- C# json数据流解析,可解决粘包、断包、坏包问题
- BZOJ 2243 浅谈树链剖分+线段树
- mycat全局表实战应用简析(下):多节点自增字段的处理
- Python实现排序算法
- CSS实现单行、多行文本溢出显示省略号(…)
- 用GridView来显示文件链接
- selenium学习---1
- web.xml配置详解
- Kotlin学习(7)高阶函数和函数类型
- tensorflow学习