本来只是想练练LCT,没想到是个线段树

对于操作1:诶新的颜色?这不是access吗?

也就是说,我们用一棵splay来表示一种颜色

操作2直接在LCT上乱搞……

不对啊,操作3要查子树

诶好像是静态的

那可以考虑线段树维护dfs序

现在要考虑怎么维护权值

我们发现开始的时候权值就是节点的深度

而在且只在access的时候会改变权值

试试魔改access?

原来:

for (int y=0;x;y=x,x=fa[x])
{
splay(x);
ch[x][1]=y;
update(x);
}

那么主要就是\(ch[x][1]=y\)

实际上这句话包含两个操作:清除\(ch[x][1]\),把\(y\)接到\(x\)的右儿子

清除\(ch[x][1]\),相当于把原来的重边断开

我们只考虑当前这个点改了之后的影响

注意既然他们是重边连起来的,他们原来一定是同色的

而改了之后他们就不同了,所以y的子树权值都会增加1

并且他也不会和这条到根路径上任何一个出现过的颜色相同

同样,把\(y\)接到\(x\)的右儿子,意味着x和y同色了,而原来是不同的,所以y的子树权值都会减少1

线段树维护一下就好

操作2直接单点查询,类似树上前缀和就可以了

于是乎,LCT40多行……

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cctype>
#define MAXN 1000005
#define MAXM 2000005
using namespace std;
inline int read()
{
int ans=0;
char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
return ans;
}
struct edge
{
int u,v;
}e[MAXM];
int head[MAXN],nxt[MAXM],cnt;
void addnode(int u,int v)
{
e[++cnt]=(edge){u,v};
nxt[cnt]=head[u];
head[u]=cnt;
}
int dep[MAXN],fa[MAXN],up[MAXN][20];
int dfn[MAXN],pos[MAXN],tim,end[MAXN];
void dfs(int u)
{
dfn[u]=++tim;
pos[tim]=u;
for (int i=1;i<20;i++)
up[u][i]=up[up[u][i-1]][i-1];
for (int i=head[u];i;i=nxt[i])
if (!dep[e[i].v])
{
dep[e[i].v]=dep[u]+1;
up[e[i].v][0]=u;
fa[e[i].v]=u;
dfs(e[i].v);
}
end[u]=tim;
}
int lca(int x,int y)
{
if (dep[x]<dep[y]) swap(x,y);
int t=dep[x]-dep[y];
for (int i=0;(1<<i)<=t;i++)
if (t&(1<<i))
x=up[x][i];
if (x==y) return x;
for (int i=19;i>=0;i--)
if (up[x][i]!=up[y][i])
x=up[x][i],y=up[y][i];
return up[x][0];
}
namespace SGT
{
#define lc p<<1
#define rc p<<1|1
struct SegmentTree
{
int l,r;
int lazy;
int mx;
}t[MAXN<<2];
void pushup(int p){t[p].mx=max(t[lc].mx,t[rc].mx);}
void pushlazy(int p,int v){t[p].mx+=v,t[p].lazy+=v;}
void pushdown(int p)
{
if (t[p].lazy)
{
pushlazy(lc,t[p].lazy);
pushlazy(rc,t[p].lazy);
t[p].lazy=0;
}
}
void build(int p,int l,int r)
{
t[p].l=l,t[p].r=r;
if (l==r){t[p].mx=dep[pos[l]];return;}
int mid=(l+r)>>1;
build(lc,l,mid),build(rc,mid+1,r);
pushup(p);
}
void modify(int p,int l,int r,int v)
{
if (l<=t[p].l&&t[p].r<=r) return pushlazy(p,v);
if (r<t[p].l||t[p].r<l) return;
pushdown(p);
if (l<=t[lc].r) modify(lc,l,r,v);
if (t[rc].l<=r) modify(rc,l,r,v);
pushup(p);
}
int querymax(int p,int l,int r)
{
pushdown(p);
if (l<=t[p].l&&t[p].r<=r) return t[p].mx;
if (r<t[p].l||t[p].r<l) return 0;
int ans=0;
if (l<=t[lc].r) ans=max(ans,querymax(lc,l,r));
if (t[rc].l<=r) ans=max(ans,querymax(rc,l,r));
return ans;
}
int query(int p,int k)
{
pushdown(p);
if (t[p].l==t[p].r) return t[p].mx;
if (k<=t[lc].r) return query(lc,k);
else return query(rc,k);
}
}
using namespace SGT;
namespace Splay
{
int ch[MAXN][2];
bool isroot(int x){return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;}
int get(int x){return ch[fa[x]][1]==x;}
void rotate(int x)
{
int y=fa[x],z=fa[y];
int l=get(x),r=l^1;
int w=ch[x][r];
if (!isroot(y)) ch[z][get(y)]=x;
ch[x][r]=y,ch[y][l]=w;
if (w) fa[w]=y;
fa[y]=x,fa[x]=z;
}
void splay(int x)
{
while (!isroot(x))
{
int y=fa[x];
if (!isroot(y))
{
if (get(x)==get(y)) rotate(y);
else rotate(x);
}
rotate(x);
}
}
}
using namespace Splay;
namespace LCT
{
int findroot(int x){while (ch[x][0]) x=ch[x][0];return x;}
void access(int x)
{
int w;
for (int y=0;x;y=x,x=fa[x])
{
splay(x);
if (ch[x][1]){w=findroot(ch[x][1]),modify(1,dfn[w],end[w],1);}
if (ch[x][1]=y){w=findroot(y),modify(1,dfn[w],end[w],-1);}
}
}
}
using namespace LCT;
int main()
{
int n,m;
n=read(),m=read();
for (int i=1;i<n;i++)
{
int u,v;
u=read(),v=read();
addnode(u,v),addnode(v,u);
}
dep[1]=1;
dfs(1);
build(1,1,n);
while (m--)
{
int op,x,y,l;
op=read(),x=read();
int ans;
switch(op)
{
case 1:access(x);break;
case 2:
y=read();
l=lca(x,y);
ans=query(1,dfn[x]);
ans+=query(1,dfn[y]);
ans-=(query(1,dfn[l])<<1);
printf("%d\n",ans+1);
break;
case 3:
printf("%d\n",querymax(1,dfn[x],end[x]));
}
}
return 0;
}

【SDOI2017】树点染色【线段树+LCT】的更多相关文章

  1. codevs 1191 树轴染色 线段树区间定值,求和

    codevs 1191 树轴染色 Time Limit: 1 Sec  Memory Limit: 256 MB 题目连接 http://www.codevs.cn/problem/1191/ Des ...

  2. 【BZOJ2243】[SDOI2011]染色 树链剖分+线段树

    [BZOJ2243][SDOI2011]染色 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的 ...

  3. bzoj2243[SDOI2011]染色 树链剖分+线段树

    2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 9012  Solved: 3375[Submit][Status ...

  4. B20J_2243_[SDOI2011]染色_树链剖分+线段树

    B20J_2243_[SDOI2011]染色_树链剖分+线段树 一下午净调这题了,争取晚上多做几道. 题意: 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成 ...

  5. 2243: [SDOI2011]染色 树链剖分+线段树染色

    给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段), 如“112221”由3段组 ...

  6. BZOJ - 2243 染色 (树链剖分+线段树+区间合并)

    题目链接 线段树维护区间连续段个数即可.设lc为区间左端点颜色,rc为区间右端点颜色,则合并两区间的时候,如果左区间右端点和右区间左端点颜色相同,则连续段个数-1. 在树链上的区间合并可以定义一个结构 ...

  7. BZOJ2243 [SDOI2011]染色(树链剖分+线段树合并)

    题目链接 BZOJ2243 树链剖分 $+$ 线段树 线段树每个节点维护$lc$, $rc$, $s$ $lc$代表该区间的最左端的颜色,$rc$代表该区间的最右端的颜色 $s$代表该区间的所有连续颜 ...

  8. BZOJ2243 (树链剖分+线段树)

    Problem 染色(BZOJ2243) 题目大意 给定一颗树,每个节点上有一种颜色. 要求支持两种操作: 操作1:将a->b上所有点染成一种颜色. 操作2:询问a->b上的颜色段数量. ...

  9. 有趣的线段树模板合集(线段树,最短/长路,单调栈,线段树合并,线段树分裂,树上差分,Tarjan-LCA,势能线段树,李超线段树)

    线段树分裂 以某个键值为中点将线段树分裂成左右两部分,应该类似Treap的分裂吧(我菜不会Treap).一般应用于区间排序. 方法很简单,就是把分裂之后的两棵树的重复的\(\log\)个节点新建出来, ...

  10. [luogu3676] 小清新数据结构题 [树链剖分+线段树]

    题面 传送门 思路 本来以为这道题可以LCT维护子树信息直接做的,后来发现这样会因为splay形态改变影响子树权值平方和,是splay本身的局限性导致的 所以只能另辟蹊径 首先,我们考虑询问点都在1的 ...

随机推荐

  1. 【CF802C】 Heidi and Library (hard)(费用流)

    题目链接 感觉跟餐巾计划问题有点像.费用流. 决定每天买不买不太好搞,不如先把所有东西都买进来,再卖掉不必要的. 拆点,每个点拆成\(x,y\). 源点向每个点的\(x\)连费用为当天的价格,流量为1 ...

  2. 41、用Python实现一个二分查找的函数

    data = [1, 3, 6, 7, 9, 12, 14, 16, 17, 18, 20, 21, 22, 23, 30, 32, 33, 35] def binary_search(dataset ...

  3. MSSQL 详解SQL Server连接(内连接、外连接、交叉连接)

    在查询多个表时,我们经常会用“连接查询”.连接是关系数据库模型的主要特点,也是它区别于其它类型数据库管理系统的一个标志. 什么是连接查询呢? 概念:根据两个表或多个表的列之间的关系,从这些表中查询数据 ...

  4. 安装JDK环境变量的配置

    设置环境变量 在java中需要设置三个环境变量(1.5之后不用再设置classpath了,但是个人强烈建议继续设置以保证向下兼容问题) JDK安装完成之后我们用来设置环境变量:右击”我的电脑“,选择” ...

  5. PHP对象3: public / private / protected

    <?php /* public 可继承, 内外可访问 private 不可, 只内部访问 protected 可继承, 只内部 */ class A{ protected $name; priv ...

  6. JavaScript变量命名规则:匈牙利命名法

    匈牙利命名法语法 变量名=类型+对象描述 类型指变量的类型 对象描述指对象名字全称或名字的一部分,要求有明确含义,命名要容易记忆容易理解. 提示 虽然JavaScript变量表面上没有类型,但是Jav ...

  7. Morris Traversal方法遍历

    实现二叉树的遍历且只需要O(1)的空间. 参考:http://www.cnblogs.com/AnnieKim/archive/2013/06/15/MorrisTraversal.html

  8. before_request after_request

    Flask我们已经学习很多基础知识了,现在有一个问题 我们现在有一个 Flask 程序其中有3个路由和视图函数,如下: from flask import Flask app = Flask(__na ...

  9. Django-manage.py

    一.manage.py命令选项 manage.py是每个Django项目中自动生成的一个用于管理项目的脚本文件,需要通过python命令执行.manage.py接受的是Django提供的内置命令. 内 ...

  10. hdu 5833(欧拉路)

    The Best Path Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)Tot ...