[题解]luogu_P3313_旅行(树剖

Posted superminivan

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[题解]luogu_P3313_旅行(树剖相关的知识,希望对你有一定的参考价值。

树剖,其实信仰就是颜色,对于这种颜色问题我们可以考虑维护每种颜色的位置,对每种颜色用数据结构维护,可以支持合并之类的一些操作,这里可以对每个颜色维护一个动态开点权值线段树,线段树维护此颜色某点的权值,没有就是不在这个颜色里,修改直接删除再修改之类的即可

#include<bits/stdc++.h>
#define mid ((l+r)>>1)
using namespace std;
const int maxn=100009;
int n,m,w[maxn],c[maxn],tot;
struct node{
    int v,nxt;
}e[maxn<<1];
int head[maxn],cnt;
inline void add(int u,int v){
    e[++cnt].v=v;e[cnt].nxt=head[u];head[u]=cnt;
}
int fa[maxn],dep[maxn],siz[maxn],son[maxn],dfn[maxn],id[maxn],top[maxn];
void dfs1(int x,int f){
    siz[x]=1;dep[x]=dep[f]+1;fa[x]=f;
    for(int i=head[x];i;i=e[i].nxt){
        int y=e[i].v;if(y==f)continue;
        dfs1(y,x);
        siz[x]+=siz[y];
        if(siz[y]>siz[son[x]])son[x]=y;
    }
}
void dfs2(int x,int tp){
    top[x]=tp;
    dfn[x]=++tot;
    id[tot]=x;
    if(!son[x])return;
    dfs2(son[x],tp);
    for(int i=head[x];i;i=e[i].nxt){
        int y=e[i].v;if(y==fa[x]||y==son[x])continue;
        dfs2(y,y);
    }
}
int root[maxn],ls[maxn*30],rs[maxn*30];
struct ttt{
    int mx,sum;
}t[maxn*30];
inline void upd(int x){
    t[x].sum=t[ls[x]].sum+t[rs[x]].sum;
    t[x].mx=max(t[ls[x]].mx,t[rs[x]].mx);
}
inline void change(int &x,int l,int r,int pos,int val){//dfs序为pos,评级val 
    if(!x)x=++tot;
    t[x].mx=max(t[x].mx,val),t[x].sum+=val;
    if(l==r)return;
    if(pos<=mid)change(ls[x],l,mid,pos,val);
    else change(rs[x],mid+1,r,pos,val);
}
inline void del(int &x,int l,int r,int pos){
    if(l==r){
        t[x].sum=t[x].mx=0;return;
    }
    if(pos<=mid)del(ls[x],l,mid,pos);
    else del(rs[x],mid+1,r,pos);
    upd(x);
}
inline int qSum(int x,int l,int r,int L,int R){
    if(L<=l&&r<=R)return t[x].sum;
    int ans=0;
    if(L<=mid)ans+=qSum(ls[x],l,mid,L,R);
    if(R>mid)ans+=qSum(rs[x],mid+1,r,L,R);
    return ans;
}
inline int qMx(int x,int l,int r,int L,int R){
    if(L<=l&&r<=R)return t[x].mx;
    int ans=0;
    if(L<=mid)ans=max(ans,qMx(ls[x],l,mid,L,R));
    if(R>mid)ans=max(ans,qMx(rs[x],mid+1,r,L,R));
    return ans;
}
inline int qMxRoute(int x,int y,int val){
    int ans=0;
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        ans=max(ans,qMx(root[val],1,n,dfn[top[x]],dfn[x]));
        x=fa[top[x]];
    }
    if(dep[x]<dep[y])swap(x,y);
    ans=max(ans,qMx(root[val],1,n,dfn[y],dfn[x]));
    return ans;
}
inline int qSumRoute(int x,int y,int val){
    int ans=0;
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        ans+=qSum(root[val],1,n,dfn[top[x]],dfn[x]);
        x=fa[top[x]];
    }
    if(dep[x]<dep[y])swap(x,y);
    ans+=qSum(root[val],1,n,dfn[y],dfn[x]);
    return ans;
}
int main(){
//    freopen("test.out","w",stdout);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)scanf("%d%d",&w[i],&c[i]);
    for(int i=1,u,v;i<n;i++){
        scanf("%d%d",&u,&v);add(u,v);add(v,u);
    }
    dfs1(1,0);dfs2(1,1);
    for(int i=1;i<=n;i++)change(root[c[i]],1,n,dfn[i],w[i]);
    char op[10];
    for(int i=1,x,y;i<=m;i++){
        scanf("%s",op);
        scanf("%d%d",&x,&y);
        if(op[1]==C){
            del(root[c[x]],1,n,dfn[x]);
            change(root[y],1,n,dfn[x],w[x]);
            c[x]=y;
        }
        else if(op[1]==W){
            del(root[c[x]],1,n,dfn[x]);
            change(root[c[x]],1,n,dfn[x],y);
            w[x]=y;
        }
        else if(op[1]==S)printf("%d
",qSumRoute(x,y,c[x]));
        else printf("%d
",qMxRoute(x,y,c[x]));
    }
}

 

以上是关于[题解]luogu_P3313_旅行(树剖的主要内容,如果未能解决你的问题,请参考以下文章

luogu3313 [SDOI2014]旅行

luoguP3313 [SDOI2014]旅行

题解SDOI2014旅行

[题解]luogu_P4886_快递员(点分治

[luogu P3313] [SDOI2014]旅行

[题解/模板]luogu_P3942_(树上覆盖问题