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
原创粉丝点击