[xsy2913]enos
题意:一棵树,点有$0,1,2$三种颜色,支持路径修改颜色和查询点所在同色连通块的大小
lcm太可怕了,于是去问了sk,得到一个优质做法
考虑lct维护子树信息,$vs_{x,i}$为$x$的虚儿子中,以颜色为$i$的节点为根的同色连通块大小之和,$s_{x,i}$表示splay上$x$的子树$vs_{x,i}$之和,切换虚实时更新$vs$,splay上pushup时更新$s$即可
如果每时每刻都保持同一棵splay中点的颜色都相同,那么询问时只需模仿access的过程,不停往上拼接同色splay,最后得到的splay的根节点$x$的$s_{x,c_x}+siz_x$就是答案,我们把这种access称为按颜色access
现在考虑修改,先求lca,把修改拆成两个祖先后代链,假设这条祖先后代链为$y\rightarrow x$,$y$是$x$的祖先
先对$fa_y$按颜色access,再对$x\rightarrow y$无条件access,对得到的splay打标记即可
这棵splay可能会作为某个点的虚儿子,看起来要一直往上更新,实际上最多更新往上的两棵splay即可
设往上的三棵splay为$T_1,T_2,T_3$,因为$T_1$是按颜色access得到的,所以$c_{T_1}\neq c_{T_2}$
首先$T_1$显然需要更新,然后因为$T_2$需要用到$T_1$的信息,所以当$y\rightarrow x$这条链在修改前或修改后的颜色$=c_{T_1}$时,$T_1$的$s_{x,c_{T_1}}$会变化,进而影响$T_2$的$s_{x,c_{T_1}}$
幸运地,$T_3$只需要用到$T_2$的$s_{x,c_{T_2}}$信息,又因为$c_{T_1}\ne c_{T_2}$,所以从$T_3$开始往上的那些splay都无需更新
最后是无条件access所引发的一些小问题,在按颜色access时,我们可以快速而准确地更新一个节点的$vs$,但无条件access时,splay中可能含有不同颜色的点,这时不能直接用$s_{x,c_x}+siz_x$来计算$x$对父亲的$vs$的贡献
解决方法很简单:在拼接$x$和$y$之前先算出$x$对父亲的旧贡献,减掉即可,又因为一个节点原来的实儿子的splay子树中都是同颜色的点,这部分的贡献可以直接按原来的方法算
于是整道题就做完了,这个题还是挺好的==
再次orzsk和dtz两位人形自走dspedia
#include<stdio.h> #include<algorithm> using namespace std; int n; namespace t{ int h[100010],nex[100010],to[100010],M; void add(int a,int b){ M++; to[M]=b; nex[M]=h[a]; h[a]=M; } int fa[100010][17],dep[100010],siz[100010]; void dfs(int x){ dep[x]=dep[fa[x][0]]+1; siz[x]=1; for(int i=h[x];i;i=nex[i]){ if(to[i]!=fa[x][0]){ dfs(to[i]); siz[x]+=siz[to[i]]; } } } void work(){ int i,j; for(i=2;i<=n;i++){ scanf("%d",fa[i]); add(fa[i][0],i); } dfs(1); for(j=1;j<17;j++){ for(i=1;i<=n;i++)fa[i][j]=fa[fa[i][j-1]][j-1]; } } int lca(int x,int y){ int i; if(dep[x]<dep[y])swap(x,y); for(i=16;i>=0;i--){ if(dep[fa[x][i]]>=dep[y])x=fa[x][i]; } if(x==y)return x; for(i=16;i>=0;i--){ if(fa[x][i]!=fa[y][i]){ x=fa[x][i]; y=fa[y][i]; } } return fa[x][0]; } } namespace l{ int ch[100010][2],fa[100010],r[100010],siz[100010],s[100010][3],vs[100010][3],d[100010],c[100010]; #define ls ch[x][0] #define rs ch[x][1] void pushup(int x){ for(int i=0;i<3;i++)s[x][i]=s[ls][i]+s[rs][i]+vs[x][i]; r[x]=rs?r[rs]:x; siz[x]=siz[ls]+siz[rs]+1; } void rot(int x){ int y,z,f,b; y=fa[x]; z=fa[y]; f=ch[y][0]==x; b=ch[x][f]; fa[x]=z; fa[y]=x; if(b)fa[b]=y; ch[x][f]=y; ch[y][f^1]=b; if(ch[z][0]==y)ch[z][0]=x; if(ch[z][1]==y)ch[z][1]=x; pushup(y); pushup(x); } void set(int x,int v){ d[x]=c[x]=v; } void pushdown(int x){ if(~d[x]){ if(ls)set(ls,d[x]); if(rs)set(rs,d[x]); d[x]=-1; } } bool isrt(int x){return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;} void gao(int x){ if(!isrt(x))gao(fa[x]); pushdown(x); } void splay(int x){ gao(x); int y,z; while(!isrt(x)){ y=fa[x]; z=fa[y]; if(!isrt(y))rot((ch[z][0]==y)^(ch[y][0]==x)?x:y); rot(x); } } void work(){ int i; for(i=1;i<=n;i++){ fa[i]=t::fa[i][0]; r[i]=i; d[i]=-1; siz[i]=1; vs[i][0]=s[i][0]=t::siz[i]-1; } } #define v(x) (s[x][c[x]]+siz[x]) void access(int x,int z){ int y,t; splay(x); y=0; t=0; while(x){ splay(x); if(r[x]==z)break; vs[x][c[rs]]+=v(rs); vs[x][c[y]]-=t; t=v(x); rs=y; pushup(x); y=x; x=fa[x]; } } int query(int x){ int y,v; splay(x); y=0; v=c[x]; while(x){ splay(x); if(c[x]!=v)break; vs[x][c[rs]]+=v(rs); vs[x][c[y]]-=v(y); rs=y; pushup(x); y=x; x=fa[x]; } return s[y][v]+siz[y]; } } void modify(int x,int y,int v){ using namespace l; int z=t::fa[y][0]; if(z){ query(z); splay(z); if(fa[z]){ splay(fa[z]); vs[fa[z]][c[z]]-=v(z); } splay(y); vs[z][c[y]]-=v(y); } access(x,z); splay(x); set(x,v); if(z){ splay(y); vs[z][c[y]]+=v(y); pushup(z); if(fa[z]){ vs[fa[z]][c[z]]+=v(z); pushup(fa[z]); } } } int main(){ int m,i,x,y,z,k; scanf("%d%d",&n,&m); t::work(); l::work(); while(m--){ scanf("%d",&i); if(i==1){ scanf("%d%d%d",&x,&y,&z); k=t::lca(x,y); modify(x,k,z); modify(y,k,z); }else{ scanf("%d",&x); printf("%d\n",l::query(x)); } } }
[xsy2913]enos的更多相关文章
- 【xsy2913】 enos 动态dp
题目大意:给你一棵 $n$个点 以 $1$为根 的树,每个点有$ 0,1,2 $三种颜色之一,初始时整棵树的颜色均为 $0$. $m$ 次操作, 每次操作形如: 1 x y c : 将 $x$到$y$ ...
- ng-table 简单实例
今天用的AngularJs需要做个分页,于是用ng-table去实现,不过这个官网感觉有点坑,说的不够清楚. 下面实现了一个Demo实力,代码如下: <!DOCTYPE html> < ...
- AngularJs 动态加载模块和依赖
最近项目比较忙额,白天要上班,晚上回来还需要做Angular知识点的ppt给同事,毕竟年底要辞职了,项目的后续开发还是需要有人接手的,所以就占用了晚上学习的时间.本来一直不打算写这些第三方插件的学习笔 ...
- ui-grid
html代码: <html ng-app="myApp"> <head> <meta charset="utf- ...
- [转]ng-grid
本文转自:http://angular-ui.github.io/ui-grid/ Getting Started Steps for getting started (example on righ ...
- IGS_学习笔记10_IREP监控SOA Integration和日志设定(案例)
20150506 Created By BaoXinjian
- CentOS7.1 使用资源搜集
1.配置java环境 -openjdk* 测试 java -version 2.安装Tomcat8.0.35 点击题目可以参考源网页,但有些代码无法执行,更改如下(亲测可行): 一定要先安装java环 ...
- [转帖][超级少儿不宜]一氧化氮(NO),为什么亚洲人是最硬
阴茎科学:一氧化氮(NO),为什么亚洲人是最硬 尼堪巴图鲁 关注他 2,911 人赞同了该文章 https://zhuanlan.zhihu.com/p/55941740 超级少儿不宜.. ...
- 物联网全景动态图谱2.0|PaaS物联网平台汇总(上篇)
物联网智库 原创 物联网智库 整理发布 转载请注明来源和出处 ------ [导读] ------ 毫无疑问,2018年物联网对行业的深度变革才刚刚开启. 物联网产业链企业的质与量将进入全面爆 ...
随机推荐
- spring-boog-测试打桩-Mockito
Mockito用于测试时进行打桩处理:通过它可以指定某个类的某个方法在什么情况下返回什么样的值. 例如:测试 controller时,依赖 service,这个时候就可以假设当调用 service 某 ...
- .net基础初学Android
第一阶段:Java面向对象编程 1.Java基本数据类型与表达式,分支循环. 2.String和StringBuffer的使用.正则表达式. 3.面向对象的抽象,封装,继承,多态,类与对象,对象初始化 ...
- 阿里妈妈MLR模型(论文)
论文来源:https://arxiv.org/abs/1704.05194v1 阿里技术:https://mp.weixin.qq.com/s/MtnHYmPVoDAid9SNHnlzUw?scene ...
- Python基础 - 正则表达式
Python自带正则表达式模块,即re模块. 导入正则模块: import re 用dir()函数查看re模块内的属性和方法: dir(re)
- caffe细节
1.BN层参数设置 在训练时所有BN层要设置use_global_stats: false(也可以不写,caffe默认是false) 在测试时所有BN层要设置use_global_stats: tru ...
- nginx防止DDOS攻击
防御DDOS是一个系统工程,攻击花样多,防御的成本高瓶颈多,防御起来即被动又无奈.DDOS的特点是分布式,针对带宽和服务攻击,也就是四层流量攻击和七层应用攻击,相应的防御瓶颈四层在带宽,七层的多在架构 ...
- ***四种参数传递的形式——URL,超链接,js,form表单
什么时候用GET, 查,删 什么时候用POST,增,改 (特列:登陆用Post,因为不能让用户名和密码显示在URL上) 4种get传参方式 <html xmlns="http:// ...
- GridLayout 计算器
<?xml version="1.0" encoding="utf-8"?> <GridLayout xmlns:android=" ...
- CCF CSP 201412-3 集合竞价
CCF计算机职业资格认证考试题解系列文章为meelo原创,请务必以链接形式注明本文地址 CCF CSP 201412-3 集合竞价 问题描述 某股票交易所请你编写一个程序,根据开盘前客户提交的订单来确 ...
- day1作业:编写登陆接口
作业一:编写登陆接口 1.输入用户名和密码 2.认证成功后显示欢迎信息 3.输错三次后锁定 思路:要求是编写登陆接口,那么要有一个存放用户信息的模块:三次后锁定,要有一个存放锁定用户信息的模块:我们知 ...