[SDOI 2014] [JZOJ 3625] 旅行

Description

一棵树,每个节点有权值和颜色。询问有一下几种:

  1. 询问从u到v的路径上与u相同颜色的节点的权值和(保证u与v颜色相同)
  2. 询问从u到v的路径上与u相同颜色的节点的权值的MAX(保证u与v颜色相同)
  3. 修改节点v的权值
  4. 修改节点v的颜色

Analysis

若不考虑颜色,那么这就是一个裸的链剖(链剖裸题)。

在线做法

由于还没有搞出来,留坑待填。

离线大法

首先,我们要高呼:离线大法好!离线大法好!离线大法好!
我们可以把相同颜色类型的操作排序在一起,操作原顺序为第二关键字。
把修改颜色操作看成是添加一个节点,到下一组颜色时为了不影响,应该再删除此节点。预处理也要看成是操作,也要拆成添加和删除。这样经过我们的转换后,各个颜色的操作之间就不影响了,变成了裸的链剖,就直接用线段树维护即可。

Key Code

    fo(i,1,n)
    {
        scanf("%d %d\n",&a[i],&c[i]);
        b[++Q].tp=2,b[Q].x=i,b[Q].y=a[i],b[Q].id=Q,b[Q].c=c[i];
    }
    fo(i,1,n-1)
    {
        scanf("%d %d\n",&u,&v);
        link(u,v),link(v,u);
    }
    dfs1(1,0,1);
    dfs2(1,0,1);
    char ch;
    fo(i,1,_)
    {
        scanf("%c%c %d %d\n",&ch,&ch,&x,&y);
        b[++Q].x=x,b[Q].y=y,b[Q].id=Q,b[Q].ps=i;
        if(ch=='S') b[Q].tp=0,bz[i]=1;
        else
        if(ch=='M') b[Q].tp=1,bz[i]=1;
        else
        if(ch=='W') b[Q].tp=2,a[x]=y;
        else
        {
            b[Q].tp=2,b[Q].c=y,b[Q].y=a[x];
            b[++Q].tp=2,b[Q].x=x,b[Q].y=0,b[Q].id=Q,b[Q].c=c[x];
            c[x]=y;
            continue;
        }
        b[Q].c=c[x];
    }
    fo(i,1,n) b[++Q].tp=2,b[Q].x=i,b[Q].y=0,b[Q].id=Q,b[Q].c=c[i];
    sort(b+1,b+Q+1,cmp);
    fo(i,1,Q)
    {
        if(b[i].tp<2) ans[b[i].ps]=solve(b[i].x,b[i].y,b[i].tp);
        else change(1,1,n,w[b[i].x],b[i].y);
    }
    fo(i,1,_)
        if(bz[i]) printf("%d\n",ans[i]);

你可能感兴趣的:(线段树,离线,树链剖分)