HDU 5893List wants to travel(树链剖分-区间合并-区间更新-入边)

来源:互联网 发布:网络管理视频教程下载 编辑:程序博客网 时间:2024/05/16 19:34

题意:

找书上路径的有多少种不同颜色的更换

思路:

和网上说的一样。。先刷了染色(树链剖分-入点)再来刷这题。。然而发现和直接给点权值不同,给边权值显然麻烦的多,做了两个小时,也没讨论清楚。找了篇思路清晰的博客改了改查询部分就AC了。查询部分有详细注释,就不多记录了,当板子直接上代码

#include <map>#include <set>#include <queue>#include <cmath>#include <cstdio>#include <cstring>#include <cstdlib>#include <iostream>#include <algorithm>using namespace std;const int MAXN = 40010;struct node {    int left,right;    int left_color,right_color;    int sum;    int lazy;}t[MAXN*4];struct Edge{    int to,next,w;} edge[MAXN<<1];int fa[MAXN],son[MAXN],siz[MAXN],dep[MAXN],top[MAXN],id[MAXN],val[MAXN];int n,q;int col[MAXN];int topw= 0;int tot ,head[MAXN];int cnt=0;int fp[MAXN];void dfs1(int u,int f,int d){    dep[u]=d;    siz[u]=1;    fa[u]=f;    for(int i =head[u]; i!=-1; i=edge[i].next)    {        int v=edge[i].to;        if(v==fa[u])            continue;        val[v]=edge[i].w;        dfs1(v,u,d+1);        siz[u]+=siz[v];        if(siz[son[u]]<siz[v]||son[u]==-1)            son[u]=v;    }}void getpos(int u,int sp){    top[u] = sp;    id[u] =++topw;    ///id是点的编号,fp[id[u]]是一个对于点与自身编号的映射    fp[id[u]] = u;    if(son[u] == -1)return ;    getpos(son[u],sp);    for(int i = head[u]; ~i ; i = edge[i].next)    {        int v = edge[i].to;        if(v != son[u] && v != fa[u])            getpos(v,v);    }}void push_up(int i){    t[i].sum=t[i<<1].sum+t[i<<1|1].sum;    if(t[i<<1].right_color==t[i<<1|1].left_color)        t[i].sum--;    t[i].right_color=t[i<<1|1].right_color;    t[i].left_color=t[i<<1].left_color;}void push_down(int i){    if(t[i].lazy)    {        t[i<<1|1].lazy=t[i<<1].lazy=t[i].lazy;        t[i<<1].left_color=t[i<<1].right_color=t[i].lazy;        t[i<<1|1].left_color=t[i<<1|1].right_color=t[i].lazy;        t[i<<1|1].sum=t[i<<1].sum=t[i].sum;        t[i].lazy=0;    }}void build(int i,int left,int right){    t[i].left=left,t[i].right=right,t[i].lazy=0;    if(left==right)    {        t[i].left_color=val[fp[left]];        t[i].right_color=val[fp[left]];        t[i].sum=1;        return ;    }    int mid=(t[i].left+t[i].right)>>1;    build(i<<1,left,mid);    build(i<<1|1,mid+1,right);    push_up(i);    return ;}void update(int i,int left,int right,int w){    if(left<=t[i].left&&t[i].right<=right)    {        t[i].lazy=w;        t[i].left_color=t[i].right_color=w;        t[i].sum=1;        return ;    }    push_down(i);    int mid=(t[i].left+t[i].right)>>1;    if(mid>=left)    {        update(i<<1,left,right,w);    }    if(mid<right)    {        update(i<<1|1,left,right,w);    }    push_up(i);}int right_color = 0;int ANS = 0;///这个查询部分处理效果为:  在查一段区间时,如果左侧线段树的右端等于右侧线段树的左端就--,基本的线段树的区间合并的应用node query(int rt,int l,int r,int L,int R){    if(L<=l && r<=R)    {        return t[rt];    }    push_down(rt);    int mid = (l+r) >> 1;    if(R<=mid) return query(rt<<1,l,mid,L,R);    else if(L>mid) return query(rt<<1|1,mid+1,r,L,R);    else    {        node p1 = query(rt<<1,l,mid,L,R);        node p2 = query(rt<<1|1,mid+1,r,L,R);        node res;        res.sum = p1.sum + p2.sum;        res.left_color = p1.left_color;        res.right_color = p2.right_color;        if(p1.right_color==p2.left_color) res.sum--;        return res;    }}int solve(int x,int y){    int ans = 0;    int cx=-1,cy=-1;    ///对于每个树链剖分的效果来说,先处理深度大的部分,这样每次会得到一个当前处理链部分的顶端left_color 保存为cx, 如果下一次链的末端    ///与顶端cx颜色相同就 --     while(top[x]!=top[y])    {        if(dep[top[x]]<dep[top[y]])        {            swap(x,y);swap(cx,cy);        }        node tmp = query(1,1,n,id[top[x]],id[x]);        ans += tmp.sum;        if(tmp.right_color==cx) ans--;        cx = tmp.left_color;        x = fa[top[x]];    }    ///如果x某一次结果恰好是y的轻链的父节点,那么此时会跑到x==y的情况,既然如此就需要减去当前点的值    if(x==y)    {        if(cx==cy)ans--;        return ans;    }    ///如果x,y为同一条重链上的情况:    ///判断之前的链与当前链的关系: 因为 cy初始必定为-1,需要判断前一条链与当前链的关系    ///如果x,从某条轻链转移到此重链,然而dep[x]仍然比dep[y]小,那么y在x的上面,因此找的时候直接找cx和tmp的末端,反之同理    if(dep[x]<dep[y])    {        swap(x,y);swap(cx,cy);    }    node tmp = query(1,1,n,id[son[y]],id[x]);    ans += tmp.sum;    if(tmp.left_color == cy) ans--;     if(tmp.right_color == cx) ans--;    return ans;}void change(int u,int v,int w){    int tpu=top[u],tpv=top[v];    while(tpu!=tpv)    {        if(dep[tpu]<dep[tpv])        {            swap(u,v);            swap(tpu,tpv);        }        update(1,id[tpu],id[u],w);        u=fa[tpu];        tpu=top[u];    }    if(u==v) return ;    if(dep[u]>dep[v])        swap(u,v);    update(1,id[son[u]],id[v],w);}void addedge(int u,int v,int w){    edge[tot].w = w,edge[tot].to = v,edge[tot].next = head[u],head[u] = tot++;}int main(){    while(~scanf("%d%d",&n,&q) )    {    topw=0,tot=0;    memset(son,-1,sizeof(son));     memset(head,-1,sizeof(head));    int u,v,w,a,b,c;    for(int i =1; i < n; i++)    {        scanf("%d%d%d",&u,&v,&w);        addedge(u,v,w);        addedge(v,u,w);    }    dfs1(1,0,1);    getpos(1,1);    build(1,1,topw);    char op[5];    int color;    while(q--)    {        scanf("%s",op) ;        if(op[0] == 'C')        {            scanf("%d %d %d",&u,&v,&color);            change(u,v,color);        }        else        {            scanf("%d %d",&u,&v);            if(u==v)            {                printf("0\n");                continue;            }            int ans = 0;            ans +=  solve(u,v);            printf("%d\n",ans);        }    }    }    return 0;}/*9 101 2 22 3 11 7 21 4 23 5 23 6 15 8 25 9 3Query 2 3Q 8 9Q 1 8*/


阅读全文
0 0