「ZJOI2016」大森林 解题报告
「ZJOI2016」大森林
神仙题...
很显然线段树搞不了
考虑离线操作
我们只搞一颗树,从位置1一直往后移动,然后维护它的形态试试
显然操作0,1都可以拆成差分的形式,就是加入和删除
因为保证了操作2的合法性,我们不妨先不计合法性把所有点加到树中
显然每个点要连到在这个点之前的离这个点时间上最近那个1操作的点上
然后可以发现移动时1操作相当于很多个点换根
我们可以对每个1操作建一个虚点,然后就可以很方便换根了
那么如何保证查询操作呢?
可以把每个1操作的虚点大小设成0(代表它父亲边的直接长度),并按时间串起来。
这样,一个虚点的虚点儿子的子树的点其实也是它的子树了,查询的时候差dis[u]+dis[v]-dis[lca]*2就可以了
是不是以为这个0操作的区间限制就没有用了?
其实不是,注意到1操作的点可能还没出现...这时候就要把1操作删掉
Code:
#include <cstdio>
#include <cctype>
#include <algorithm>
using std::min;
using std::max;
const int N=3e5+10;
template <class T>
void read(T &x)
{
x=0;char c=getchar();
while(!isdigit(c)) c=getchar();
while(isdigit(c)) x=x*10+c-'0',c=getchar();
}
int ans[N],n,m,_n,_m,q,p[N],node,ti[N],tot,L[N],R[N];
struct koito_yuu
{
int pos,op,u,v;
koito_yuu(){}
koito_yuu(int Pos,int Op,int U,int V){pos=Pos,op=Op,u=U,v=V;}
bool friend operator <(koito_yuu a,koito_yuu b){return a.pos==b.pos?a.op<b.op:a.pos<b.pos;}
}yuu[N];
#define ls ch[now][0]
#define rs ch[now][1]
#define fa par[now]
int sum[N],ch[N][2],par[N],siz[N];
bool isroot(int now){return ch[fa][0]==now||ch[fa][1]==now;}
int identity(int now){return ch[fa][1]==now;}
void connect(int f,int now,int typ){ch[fa=f][typ]=now;}
void updata(int now){sum[now]=sum[ls]+sum[rs]+siz[now];}
void Rotate(int now)
{
int p=fa,typ=identity(now);
connect(p,ch[now][typ^1],typ);
if(isroot(p)) connect(par[p],now,identity(p));
else fa=par[p];
connect(now,p,typ^1);
updata(p),updata(now);
}
void splay(int now)
{
for(;isroot(now);Rotate(now))
if(isroot(fa))
Rotate(identity(now)^identity(fa)?now:fa);
}
int access(int now)
{
int las=0;
for(;now;las=now,now=fa) splay(now),rs=las,updata(now);
return las;
}
int LCA(int x,int y)
{
access(x);
return access(y);
}
void link(int x,int y)
{
access(x),splay(x);
par[x]=y;
}
void cat(int x)
{
access(x),splay(x);
par[ch[x][0]]=0;
ch[x][0]=0;
}
int qry(int x)
{
access(x),splay(x);
return sum[x];
}
int query(int x,int y)
{
int lca=LCA(x,y);
return qry(x)+qry(y)-(qry(lca)<<1);
}
int main()
{
read(n),read(m);
L[1]=1,R[1]=n,node=1,++tot;
for(int op,l,r,x,u,v,i=1;i<=m;i++)
{
read(op);
if(op==0) ++node,read(L[node]),read(R[node]),p[node]=i;
else if(op==1)
{
ti[++tot]=i;
link(tot,tot-1);
read(l),read(r),read(x);
l=max(L[x],l),r=min(R[x],r);
if(l>r) continue;
yuu[++q]=koito_yuu(l,-1,x,tot);
yuu[++q]=koito_yuu(r+1,0,x,tot);
}
else
{
read(x),read(u),read(v);
yuu[++q]=koito_yuu(x,++_n,u,v);
}
}
_m=tot;
for(int i=2;i<=node;i++)
{
int pos=std::upper_bound(ti+1,ti+1+_m,p[i])-ti-1;
siz[++tot]=1,sum[tot]=1;
link(tot,pos);
}
std::sort(yuu+1,yuu+1+q);
for(int j=1,i=1;i<=n;i++)
{
while(yuu[j].pos==i)
{
int u=yuu[j].u+_m-1,v=yuu[j].v;
if(u==_m) u=1;
if(yuu[j].op==-1)
{
cat(v);
link(v,u);
}
else if(yuu[j].op==0)
{
cat(v);
link(v,v-1);
}
else ans[yuu[j].op]=query(u,v==1?1:v+_m-1);
++j;
}
}
for(int i=1;i<=_n;i++) printf("%d\n",ans[i]);
return 0;
}
2019.3.11
「ZJOI2016」大森林 解题报告的更多相关文章
- @loj - 2092@ 「ZJOI2016」大森林
目录 @description@ @solution@ @accepted code@ @details@ @description@ 小 Y 家里有一个大森林,里面有 n 棵树,编号从 1 到 n. ...
- loj2092 「ZJOI2016」大森林
ref不是太懂-- #include <algorithm> #include <iostream> #include <cstring> #include < ...
- 「THUSCH 2017」大魔法师 解题报告
「THUSCH 2017」大魔法师 狗体面太长,帖链接了 思路,维护一个\(1\times 4\)的答案向量表示\(A,B,C,len\),最后一个表示线段树上区间长度,然后每次的操作都有一个转移矩阵 ...
- 「JLOI2015」管道连接 解题报告
「JLOI2015」管道连接 先按照斯坦纳树求一个 然后合并成斯坦纳森林 直接枚举树的集合再dp一下就好了 Code: #include <cstdio> #include <cct ...
- 「NOI2017」蚯蚓排队 解题报告
「NOI2017」蚯蚓排队 这题真的草 你考虑\(k\)这么小,每次合并两个串,增加的有用串的数量是\(O(k^2)\)的,暴力加入这些串,求一下这些串的Hash值,塞到Hash表里面去 这里采用类似 ...
- 「FJOI2016」神秘数 解题报告
「FJOI2016」神秘数 这题不sb,我挺sb的... 我连不带区间的都不会哇 考虑给你一个整数集,如何求这个神秘数 这有点像一个01背包,复杂度和值域有关.但是你发现01背包可以求出更多的东西,就 ...
- 「SCOI2016」背单词 解题报告
「SCOI2016」背单词 出题人sb 题意有毒 大概是告诉你,你给一堆n个单词安排顺序 如果当前位置为x 当前单词的后缀没在这堆单词出现过,代价x 这里的后缀是原意,但不算自己,举个例子比如abc的 ...
- 「NOI2015」寿司晚宴 解题报告
「NOI2015」寿司晚宴 这个题思路其实挺自然的,但是我太傻了...最开始想着钦定一些,结果发现假了.. 首先一个比较套路的事情是状压前8个质数,后面的只会在一个数出现一次的再想办法就好. 然后发现 ...
- 「SCOI2015」国旗计划 解题报告
「SCOI2015」国旗计划 蛮有趣的一个题 注意到区间互不交错,那么如果我们已经钦定了一个区间,它选择的下一个区间是唯一的,就是和它有交且右端点在最右边的,这个可以单调队列预处理一下 然后往后面跳拿 ...
随机推荐
- Requires: libc.so.6(GLIBC_2.14)(64bit)
centos6 - CentOS 6 - libc.so.6(GLIBC_2.14)(64bit) is needed by - Server Faulthttps://serverfault.com ...
- [转帖]一个ip对应多个域名多个ssl证书配置-Nginx实现多域名证书HTTPS
一个ip对应多个域名多个ssl证书配置-Nginx实现多域名证书HTTPS https://home.cnblogs.com/u/beyang/ 一台服务器,两个域名 首先购买https,获取到CA证 ...
- zookeeper的安装和启动教程
zookeeper的安装和启动 zookeeper安装包所在目录: 上传文件到虚拟机.现在本地新建一个目录setup,将zookeeper压缩包复制进去. ALT+P打开一个标签,操作如下put命令. ...
- Appium之开发环境搭建
1.下载Appium 去官方网站下载http://appium.io/# : 本次以appium-desktop-setup-1.8.0.exe 文件为例,使用桌面版就不再需要下载server版本: ...
- 九、.net core用orm继承DbContext(数据库上下文)方式操作数据库
一.创建一个DataContext普通类继承DbContext 安装程序集:Pomelo.EntityFrameworkCore.MySql 二.配置连接字符串(MySql/SqlServer都 ...
- VS2017设置背景主题
一.VS2017设置背景主题 1.下载并安装Color Theme Editor for Visual Studio 2017和MoeIDE (图中红圈中的两个插件,工具-扩展和更新-联机-右上角搜索 ...
- Linux上面部署java项目
最近做项目迁移,费了很大周折.总算顺利迁移了.其实一直以为搞不懂单用tomcat是怎么发布项目的.但还是得硬着头皮做. 不过这个是在搭建测试服务器的时候弄的.开始我就直接把程序包丢tomcat里面也能 ...
- 5.cgroup资源控制
控制组( CGroups)是 Linux 内核的一个特性,主要用来对共享资源进行隔离.限制.审计等. 只有将分配到容器的资源进行控制,才能避免多个容器同时运行时对宿主机系统的资源竞争.每个控制组是一组 ...
- CSS3 flexbox 布局 ---- flex项目属性介绍
现在介绍用在flex项目上的css 属性,html结构还是用ul, li 结构,不过内容改成1,2,3, 样式的话,直接把给 ul 设display:flex 变成flex 容器,默认主轴的方向为水平 ...
- 训练赛-Move Between Numbers
题意:给你n个数,每个数有20个数字,每两个数字之间如果相等的数字数量为17个(一定是17),就能从一个数字到达另一个数字,给你两个数字编号,求从第一个数字编号到第二个数字编号之间最少需要走几次: 解 ...