P3313 [SDOI2014] 旅行

P3313 [SDOI2014] 旅行

题意简述:

给一颗树,点有点权以及颜色,要求实现四种操作:

1.修改某点点权
2.修改某点颜色
3.求一条树上最短路(x,y)上颜色与 x,y 都相同的点的点权和,保证 x,y颜色相同
4.求一条树上最短路(x,y)上颜色与 x,y 都相同的点的点权最大值,保证 x,y颜色相同

$ 1 \le n,m,C \le 10^5$

\(C\) 表示颜色种数

Solution:

有些猎奇的树链剖分和动态开点线段树。

我们看完题目不难想到树链剖分,但是我们会发现颜色这一限制有些棘手,我们不妨转换一下,我们用树链剖分的思想得到一些连续的树链对应连续的下标区间。

然后我们维护一个动态开点线段树,其下标是又两个数字拼成的一个数: \(pos = col \cdot C + id\) 这样一来,对于一个查询,我们设 \(k=col_x\)

对于一个连续的树上下标区间,我们在线段树上查询区间 \([k*C+l,k*C+r]\) 就能得到答案了

Code:

#include<bits/stdc++.h>
#define int long long
const int N=1e5+5;
const int inf=N*N;
using namespace std;
int n,m,rt;
int col[N],w[N];
char c[N];
inline int Max(int x,int y)
{
    return x > y ? x : y;
}
//Segment_Tree
struct Segment_Tree{
    int cnt;
    struct Tree{
        int ls,rs,cnt,sum,mx;
    }t[N*40];
    void pushup(int x)
    {
        t[x].sum=t[t[x].ls].sum+t[t[x].rs].sum;
        t[x].mx = t[t[x].ls].mx > t[t[x].rs].mx ? t[t[x].ls].mx : t[t[x].rs].mx;
    }
    void insert(int &x,int l,int r,int pos,int val)
    {
        if(!x)x=++cnt;
        if(l==r){t[x].sum+=val;t[x].mx=t[x].sum;return;}
        int mid=l+r>>1;
        if(pos<=mid)insert(t[x].ls,l,mid,pos,val);
        if(mid<pos) insert(t[x].rs,mid+1,r,pos,val);
        pushup(x);
    }
    int query(int x,int l,int r,int L,int R)
    {
        if(L<=l&&r<=R)return t[x].sum;
        int mid=l+r>>1,res=0;
        if(L<=mid)res+=query(t[x].ls,l,mid,L,R);
        if(mid<R)res+=query(t[x].rs,mid+1,r,L,R);
        return res;
    }
    int ask(int x,int l,int r,int L,int R)
    {
        if(L<=l&&r<=R)return t[x].mx;
        int mid=l+r>>1,res=0;
        if(L<=mid) res = Max(res,ask(t[x].ls,l,mid,L,R));
        if(mid<R)  res = Max(res,ask(t[x].rs,mid+1,r,L,R));
        return res;
    }
}T;
struct Graph{
    int head[N];
    struct Edge{
        int to,nxt;
    }e[N<<1];
    void add(int x,int y)
    {
        e[++head[0]]=Edge{y,head[x]};
        head[x]=head[0];
    }
    int fa[N],dep[N],dfn[N],rid[N];
    int siz[N],son[N],top[N];
    void dfs1(int x,int ff)
    {
        dep[x]=dep[fa[x]=ff]+1;
        for(int i=head[x];i;i=e[i].nxt)
        {
            int y=e[i].to;
            if(y==fa[x])continue;
            dfs1(y,x);
            siz[x] += siz[y];
            son[x] = siz[son[x]] > siz[y] ? son[x] : y;
        }
    }
    void dfs2(int x,int tp)
    {
        dfn[x]=++dfn[0];rid[dfn[0]]=x;
        top[x]=tp;
        if(!son[x])return;
        dfs2(son[x],tp);
        for(int i=head[x];i;i=e[i].nxt)
        {
            int y=e[i].to;
            if(y==fa[x]||y==son[x])continue;
            dfs2(y,y);
        }
    }
    int chain_query(int x,int y,int k)
    {
        int res=0;
        while(top[x]!=top[y])
        {
            if(dep[top[x]]<dep[top[y]])swap(x,y);
            res+=T.query(rt,1,inf,k*N+dfn[top[x]],k*N+dfn[x]);
            x=fa[top[x]];
        }
        if(dep[x]<dep[y])swap(x,y);
        res+=T.query(rt,1,inf,k*N+dfn[y],k*N+dfn[x]);
        return res;
    }
    int chain_ask(int x,int y,int k)
    {
        int res=0;
        while(top[x]!=top[y])
        {
            if(dep[top[x]]<dep[top[y]])swap(x,y);
            res=Max(res,T.ask(rt,1,inf,k*N+dfn[top[x]],k*N+dfn[x]));
            x=fa[top[x]];
        }
        if(dep[x]<dep[y])swap(x,y);
        res=Max(res,T.ask(rt,1,inf,k*N+dfn[y],k*N+dfn[x]));
        return res;
    }
}G;
void work()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)scanf("%lld%lld",&w[i],&col[i]);
    for(int i=1,x,y;i<n;i++)
    {
        scanf("%lld%lld",&x,&y);
        G.add(x,y);G.add(y,x);
    }
    G.dfs1(1,0);
    G.dfs2(1,1);
    for(int i=1;i<=n;i++)
    {
        int x=G.rid[i];
        T.insert(rt,1,inf,col[x]*N+i,w[x]);
    }
    for(int i=1,x,y;i<=m;i++)
    {
        scanf("%s",c);
        scanf("%lld%lld",&x,&y);
        if(c[1]=='C')
        {
            int u=G.dfn[x];
            T.insert(rt,1,inf,col[x]*N+u,-w[x]);
            col[x]=y;
            T.insert(rt,1,inf,col[x]*N+u,w[x]);
        }
        if(c[1]=='W')
        {
            int u=G.dfn[x];
            T.insert(rt,1,inf,col[x]*N+u,y-w[x]);
            w[x]=y;
        }
        if(c[1]=='S')
        {
            int ans=G.chain_query(x,y,col[x]);
            printf("%lld\n",ans);
        }
        if(c[1]=='M')
        {
            int ans=G.chain_ask(x,y,col[x]);
            printf("%lld\n",ans);
        }
    }
}
#undef int
int main()
{
    //freopen("P3313_2.in","r",stdin);freopen("P3313.out","w",stdout);
    work();
    return 0;
}
posted @ 2024-12-25 21:39  liuboom  阅读(33)  评论(0)    收藏  举报