当前位置: 首页 > news >正文

[BZOJ]4817: [Sdoi2017]树点涂色

Time Limit: 10 Sec  Memory Limit: 128 MB

Description

  Bob有一棵n个点的有根树,其中1号点是根节点。Bob在每个点上涂了颜色,并且每个点上的颜色不同。定义一条路径的权值是:这条路径上的点(包括起点和终点)共有多少种不同的颜色。Bob可能会进行这几种操作:
  1 x:
  把点x到根节点的路径上所有的点染上一种没有用过的新颜色。
  2 x y:
  求x到y的路径的权值。
  3 x y:
  在以x为根的子树中选择一个点,使得这个点到根节点的路径权值最大,求最大权值。
  Bob一共会进行m次操作

Input

  第一行两个数n,m。
  接下来n-1行,每行两个数a,b,表示a与b之间有一条边。
  接下来m行,表示操作,格式见题目描述
  1<=n,m<=100000

Output

  每当出现2,3操作,输出一行。
  如果是2操作,输出一个数表示路径的权值
  如果是3操作,输出一个数表示权值的最大值

Sample Input

  5 6
  1 2
  2 3
  3 4
  3 5
  2 4 5
  3 3
  1 4
  2 4 5
  1 5
  2 4 5

Sample Output

  3
  4
  2
  2

Solution

  发现这个修改操作像极了LCT,于是我们直接用LCT维护这棵树,每棵Splay代表一种颜色,每个点到根的权值就是到根路径上非偏爱边(这里非偏爱边相当于两端颜色不同的边)数量加一,一开始所有点的权值就是深度,当进行access操作时,我们每把一条偏爱边设成非偏爱边,就让这条边下面那棵子树权值加一,反之减一,以dfs序建线段树维护最大值即可,1操作直接access一遍,2操作等同于询问链上非偏爱边数加一,链上非偏爱边数即x到根的非偏爱边数+y到根的非偏爱边数-2*lca(x,y)到根的偏爱边数,3操作直接查。由于LCT是均摊O(nlogn)的,我们往里面每次操作都加了一个维护线段树的工作,总复杂度O(nlogn^2)。

Code

#include<cstdio>
#include<algorithm>
using namespace std;
char B[1<<26],*S=B,C;int X;
inline int read()
{
    while((C=*S++)<'0'||C>'9');
    for(X=C-'0';(C=*S++)>='0'&&C<='9';)X=X*10+C-'0';
    return X;
}
#define MN 100000
#define LG 17
struct edge{int nx,t;}e[MN*2+5];
int h[MN+5],en,fa[LG][MN+5],d[MN+5],a[MN+5],l[MN+5],r[MN+5],cnt;
inline void ins(int x,int y)
{
    e[++en]=(edge){h[x],y};h[x]=en;
    e[++en]=(edge){h[y],x};h[y]=en;
}
namespace segtree
{
    #define L (k<<1)
    #define R (k<<1|1)
    struct node{int l,r,mx,mk;}t[MN*4+5];
    inline void up(int k){t[k].mx=max(t[L].mx,t[R].mx);}
    inline void mark(int k,int x){t[k].mx+=x;t[k].mk+=x;}
    inline void down(int k){if(t[k].mk)mark(L,t[k].mk),mark(R,t[k].mk),t[k].mk=0;}
    void build(int k,int l,int r)
    {
        if((t[k].l=l)==(t[k].r=r)){t[k].mx=a[l];return;}
        int mid=l+r>>1;
        build(L,l,mid);build(R,mid+1,r);up(k);
    }
    void add(int k,int l,int r,int x)
    {
        if(t[k].l==l&&t[k].r==r){mark(k,x);return;}
        int mid=t[k].l+t[k].r>>1;down(k);
        if(r<=mid)add(L,l,r,x);
        else if(l>mid)add(R,l,r,x);
        else add(L,l,mid,x),add(R,mid+1,r,x);
        up(k);
    }
    int query(int k,int l,int r)
    {
        if(t[k].l==l&&t[k].r==r)return t[k].mx;
        int mid=t[k].l+t[k].r>>1;down(k);
        if(r<=mid)return query(L,l,r);
        if(l>mid)return query(R,l,r);
        return max(query(L,l,mid),query(R,mid+1,r));
    }
}
namespace lct
{
    #define L(x) c[x][0]
    #define R(x) c[x][1]
    int fa[MN+5],c[MN+5][2],ll[MN+5];
    inline void up(int x){ll[x]=L(x)?ll[L(x)]:x;}
    inline bool isc(int x){return L(fa[x])==x||R(fa[x])==x;}
    void rotate(int x)
    {
        int f=fa[x],ff=fa[f],l=R(f)==x,r=l^1;
        if(isc(f))c[ff][R(ff)==f]=x;
        fa[f]=x;fa[x]=ff;fa[c[x][r]]=f;
        c[f][l]=c[x][r];up(c[x][r]=f);
    }
    void splay(int x)
    {
        for(int f;isc(x);rotate(x))
            if(isc(f=fa[x]))rotate(L(fa[f])==f^L(f)==x?x:f);
        up(x);
    }
    void access(int x)
    {
        for(int i=0,p;x;x=fa[i=x])
        {
            splay(x);
            if(R(x))segtree::add(1,l[ll[R(x)]],r[ll[R(x)]],1);
            if(i)segtree::add(1,l[ll[i]],r[ll[i]],-1);
            R(x)=i;
        }
    }
}
void dfs(int x)
{
    a[l[x]=++cnt]=d[x];
    for(int i=h[x];i;i=e[i].nx)if(e[i].t!=fa[0][x])
        lct::fa[e[i].t]=fa[0][e[i].t]=x,d[e[i].t]=d[x]+1,dfs(e[i].t);
    r[x]=cnt;
}
int lca(int x,int y)
{
    int dx=d[x]-d[y],i;
    if(dx<0)swap(x,y),dx=-dx;
    for(i=0;dx;++i,dx>>=1)if(dx&1)x=fa[i][x];
    if(x==y)return x;
    for(i=LG;i--;)if(fa[i][x]!=fa[i][y])x=fa[i][x],y=fa[i][y];
    return fa[0][x];
}
int main()
{
    fread(B,1,1<<26,stdin);
    int n,m,i,j,x,y,z;
    n=read();m=read();
    for(i=1;i<n;++i)ins(read(),read());
    dfs(1);segtree::build(1,1,n);
    for(i=1;i<LG;++i)for(j=1;j<=n;++j)fa[i][j]=fa[i-1][fa[i-1][j]];
    using segtree::query;
    while(m--)
    {
        i=read();
        if(i==1)lct::access(read());
        if(i==2)z=lca(x=read(),y=read()),
            printf("%d\n",query(1,l[x],l[x])+query(1,l[y],l[y])-(query(1,l[z],l[z])<<1)+1);
        if(i==3)x=read(),printf("%d\n",query(1,l[x],r[x])+1);
    }
}

转载于:https://www.cnblogs.com/ditoly/p/BZOJ4817.html

相关文章:

  • redis和memcahed的共同点,区别以及应用场景
  • mysql 去除密码登录
  • express中的路径区别
  • 团队作业2——需求分析原型设计
  • redis五种数据类型的实现方式,常用命令,应用场景
  • MVC前后台传值
  • idea 右键没有run和debug选项
  • 浏览器渲染优化4(styles and layout)
  • leetcode 98,判断二叉树为BST
  • redis bind not error
  • lua实现热更方式
  • 元素
  • 基础面试题:面向对象和面向过程的区别,性能对比
  • 基础面试题: JDK 和 JRE
  • 基础面试题:java内存区域
  • [译] React v16.8: 含有Hooks的版本
  • Angular 4.x 动态创建组件
  • co模块的前端实现
  • FineReport中如何实现自动滚屏效果
  • JAVA_NIO系列——Channel和Buffer详解
  • Java方法详解
  • Java新版本的开发已正式进入轨道,版本号18.3
  • leetcode388. Longest Absolute File Path
  • leetcode98. Validate Binary Search Tree
  • SpringCloud集成分布式事务LCN (一)
  • 从重复到重用
  • 机器学习中为什么要做归一化normalization
  • 开源地图数据可视化库——mapnik
  • 目录与文件属性:编写ls
  • 前端攻城师
  • 如何进阶一名有竞争力的程序员?
  • 扫描识别控件Dynamic Web TWAIN v12.2发布,改进SSL证书
  • 世界上最简单的无等待算法(getAndIncrement)
  • 无服务器化是企业 IT 架构的未来吗?
  • 7行Python代码的人脸识别
  • ​草莓熊python turtle绘图代码(玫瑰花版)附源代码
  • #define
  • #鸿蒙生态创新中心#揭幕仪式在深圳湾科技生态园举行
  • (1)Nginx简介和安装教程
  • (第61天)多租户架构(CDB/PDB)
  • (附源码)SSM环卫人员管理平台 计算机毕设36412
  • (汇总)os模块以及shutil模块对文件的操作
  • (四)汇编语言——简单程序
  • .net Application的目录
  • .Net core 6.0 升8.0
  • .NET Core 通过 Ef Core 操作 Mysql
  • .NET MVC第五章、模型绑定获取表单数据
  • .net 反编译_.net反编译的相关问题
  • .NET大文件上传知识整理
  • .NET框架类在ASP.NET中的使用(2) ——QA
  • .NET与java的MVC模式(2):struts2核心工作流程与原理
  • .net知识和学习方法系列(二十一)CLR-枚举
  • .pub是什么文件_Rust 模块和文件 - 「译」
  • .so文件(linux系统)
  • :如何用SQL脚本保存存储过程返回的结果集