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*/

嗯,就是这样