BZOJ_4867_[Ynoi2017]舌尖上的由乃_分块+dfs序

Description

由乃为了吃到最传统最纯净的美食,决定亲自开垦一片菜园。现有一片空地,由乃已经规划n个地点准备种上蔬菜。最新鲜的蔬菜需有最甘甜井水的灌溉,因此由乃将要打出两口井,分别记为井A、井B。现在问题来了,由乃可是一周目的神,为何要打井?是谁想出来的这些题面?由乃不善于搞事情,于是提出以下几个方法,再根据这些方法找出题人。方法如下:
1. 做完这个出题人出的所有题
2. 做完所有数据结构题
3. 出一道奇怪的数据结构题,而且卡常卡死所有做题的
至于为什么这样能找到出题人呢。。。我也不信她能找到我。。。(能找到岂不是更好?)
因为由乃是神,所有她有很多秒时间,她终于做完了世界上左右的数据结构题
于是该她出题了,她左思右想,出了一个简单数据结构题:
给你一个n个点的有根树,1为根,带边权,有m次操作。
1、求x的子树中第k小的深度的值,如果子树中没有k个点则输出-1;
2、将x与x父亲的边权加上k。
保证每次操作2的k以及原树的边权小于等于一个数len。
如果操作2中x为1,那么视为将x的基础深度加上了k。
由乃能不能找到出题人呢?

Input

第一行三个数n,m,len。
之后n - 1行每行两个数表示2~n每个点的父亲编号,以及他们到父亲的边权。。。
之后m行每行三个数 opt,x,k,opt表示操作种类,x,k意义如题所述。
n,m <= 100000

Output

对于每个操作1,输出一个数表示答案

Sample Input

3 5 3
1 3
2 3
1 1 3
2 3 3
1 1 3
2 1 2
1 1 3

Sample Output

6
9
11

HINT

对于所有数据,n,m <= 100000,len <= 10
因为出题人是sb,len <= 10,其实没有这个限制也可以解决这个问题

先用dfs序转化成区间问题。区间加,区间第K小。
可以二分答案转化为区间求比x小的数的个数,即每块维护一个有序二元组,表示数值和位置。
然后修改整块加标记,零散块暴力归并,时间复杂度$O(\sqrt n)$,询问对零散块暴力然后整块的二分,时间复杂度$O(\sqrt nlogn)$。
也就是说加上二分答案后时间复杂度为$O(n\sqrt nlognlogn)$,过不去此题,考虑修改块的大小。
设块大小为$size$,修改的复杂度是$O(size+n/size)$,查询的复杂度为$O((size+n/size)logn)$,如果我们把零散块预先合在一起可以优化到$O(size+n/size*logn)$。
算出$size=\sqrt nlogn$时最优,总时间复杂度为$O(n\sqrt nlogn)$。
然而复杂度对了写的丑还是过不去。。。加上register直接快了10秒多,然后因为我写的修改常数太大,块的大小应小一点更好。
手动测试是当块大小为3700时能过。
 
代码:
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <math.h>
using namespace std;
#define RR register
inline char nc() {
static char buf[100000],*p1,*p2;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int rd() {
RR int x=0;RR char s=nc();
while(s<'0'||s>'9') s=nc();
while(s>='0'&&s<='9') x=(x<<3)+(x<<1)+s-'0',s=nc();
return x;
}
#define N 100500
int head[N],to[N],nxt[N],val[N],cnt,dfn[N],son[N],L[N],R[N],block,dis[N],n,m,pos[N],mx,t[N],more[N],size,fa[N],tot;
struct A {
int v,id;
}a[N],b[N],c[N];
inline bool cmp1(const A &x,const A &y) {
return x.v<y.v;
}
inline void add(int u,int v,int w) {
to[++cnt]=v; nxt[cnt]=head[u]; head[u]=cnt; val[cnt]=w;
}
void dfs(int x) {
RR int i; dfn[x]=++tot; a[tot].v=dis[x]; a[tot].id=tot;
for(i=head[x];i;i=nxt[i]) {
dis[to[i]]=dis[x]+val[i];
dfs(to[i]);
}
son[x]=tot;
}
inline void update(int l,int r,int v) {
RR int p=pos[l],q=pos[r],i,j,k;
RR int lb=0,lc=0;
if(p==q) {
for(i=L[p];i<=R[p];i++) {
if(a[i].id<=r&&a[i].id>=l) b[++lb]=a[i],b[lb].v+=v;
else c[++lc]=a[i];
}
i=1; j=1; k=L[p];
while(i<=lb&&j<=lc) {
if(b[i].v<=c[j].v) a[k++]=b[i++];
else a[k++]=c[j++];
}
while(i<=lb) a[k++]=b[i++];
while(j<=lc) a[k++]=c[j++];
}else {
for(i=p+1;i<q;i++) more[i]+=v; lb=0,lc=0;
for(i=L[p];i<=R[p];i++) {
if(a[i].id>=l) b[++lb]=a[i],b[lb].v+=v;
else c[++lc]=a[i];
}
i=1; j=1; k=L[p];
while(i<=lb&&j<=lc) {
if(b[i].v<=c[j].v) a[k++]=b[i++];
else a[k++]=c[j++];
}
while(i<=lb) a[k++]=b[i++];
while(j<=lc) a[k++]=c[j++]; lb=0; lc=0;
for(i=L[q];i<=R[q];i++) {
if(a[i].id<=r) b[++lb]=a[i],b[lb].v+=v;
else c[++lc]=a[i];
}
i=1; j=1; k=L[q];
while(i<=lb&&j<=lc) {
if(b[i].v<=c[j].v) a[k++]=b[i++];
else a[k++]=c[j++];
}
while(i<=lb) a[k++]=b[i++];
while(j<=lc) a[k++]=c[j++];
}
}
inline int search(int l,int r,int x) {
RR int tmp=l,p=pos[l]; r++;
x-=more[p];
while(l<r) {
int mid=(l+r)>>1;
if(a[mid].v<=x) l=mid+1;
else r=mid;
}
return l-tmp;
}
inline int findt(int x) {
RR int l=1,r=t[0]+1,mid;
while(l<r) {
mid=(l+r)>>1;
if(t[mid]<=x) l=mid+1;
else r=mid;
}
return l-1;
}
inline int query(int x,int y,int k) {
if(y-x+1<k) return -1;
RR int p=pos[x],q=pos[y],i,j;
if(p==q) {
t[0]=0;
for(i=L[p];i<=R[p];i++) {
if(a[i].id>=x&&a[i].id<=y) t[++t[0]]=a[i].v+more[p];
}
}else {
t[0]=0;
RR int lb=0,lc=0;
for(i=L[p];i<=R[p];i++) {
if(a[i].id>=x) b[++lb]=a[i],b[lb].v+=more[p];
}
for(i=L[q];i<=R[q];i++) {
if(a[i].id<=y) c[++lc]=a[i],c[lc].v+=more[q];
}
i=1; j=1;
while(i<=lb&&j<=lc) {
if(b[i].v<=c[j].v) t[++t[0]]=b[i++].v;
else t[++t[0]]=c[j++].v;
}
while(i<=lb) t[++t[0]]=b[i++].v;
while(j<=lc) t[++t[0]]=c[j++].v;
}
RR int l=0,r=mx+1,mid,re;
while(l<r) {
mid=(l+r)>>1; re=0;
if(t[0]) re+=findt(mid);
for(i=p+1;i<q;i++) re+=search(L[i],R[i],mid);
if(re>=k) r=mid;
else l=mid+1;
}
return l;
}
int main() {
//freopen("a.in","r",stdin);
//freopen("a.out","w",stdout);
RR int kitty,opt;
n=rd(); m=rd(); kitty=rd();
RR int i,x,y,j;
// int ln=n,lg=1;
// while(ln) lg++,ln>>=1;
for(i=2;i<=n;i++) {
x=rd(); y=rd(); add(x,i,y);
}
// size=((int)ceil(sqrt(n)))*(lg);
// printf("%d\n",size);return 0;
size=3700;
dfs(1);
block=n/size;
for(i=1;i<=block;i++) {
L[i]=R[i-1]+1; R[i]=i*size;
sort(a+L[i],a+R[i]+1,cmp1);
mx=max(mx,a[R[i]].v);
for(j=L[i];j<=R[i];j++) pos[j]=i;
}
if(R[block]!=n) {
block++; L[block]=R[block-1]+1; R[block]=n;
sort(a+L[block],a+n+1,cmp1);
for(i=L[block];i<=n;i++) pos[i]=block;
mx=max(mx,a[n].v);
}
while(m--) {
opt=rd(); x=rd(); y=rd();
if(opt==1) {
printf("%d\n",query(dfn[x],son[x],y));
}else {
update(dfn[x],son[x],y); mx+=y;
}
}
return 0;
}

BZOJ_4867_[Ynoi2017]舌尖上的由乃_分块+dfs序的更多相关文章

  1. BZOJ_4765_普通计算姬_分块+dfs序+树状数组

    BZOJ_4765_普通计算姬_分块 Description "奋战三星期,造台计算机".小G响应号召,花了三小时造了台普通计算姬.普通计算姬比普通计算机要厉害一些 .普通计算机能 ...

  2. BZOJ4867 : [Ynoi2017]舌尖上的由乃

    首先通过DFS序将原问题转化为序列上区间加.询问区间kth的问题. 考虑分块,设块大小为$K$,每块维护排序过后的$pair(值,编号)$. 对于修改,整块的部分可以直接打标记,而零碎的两块因为本来有 ...

  3. BZOJ4867 Ynoi2017舌尖上的由乃(dfs序+分块)

    容易想到用dfs序转化为序列上的问题.考虑分块,对每块排序,修改时对于整块打上标记,边界暴力重构排序数组,询问时二分答案,这样k=sqrt(nlogn)时取最优复杂度nsqrt(nlogn)logn, ...

  4. (原创)舌尖上的c++--相逢

    引子 前些时候,我在群里出了一道题目:将变参的类型连接在一起作为字符串并返回出来,要求只用函数实现,不能借助于结构体实现.用结构体来实现比较简单: template<typename... Ar ...

  5. 舌尖上的硬件:CPU/GPU芯片制造解析(高清)(组图)

    一沙一世界,一树一菩提,我们这个世界的深邃全部蕴藏于一个个普通的平凡当中.小小的厨房所容纳的不仅仅是人们对味道的情感,更有推动整个世界前进的动力.要想理解我们的世界,有的时候只需要细细品味一下我们所喜 ...

  6. BZOJ_3252_攻略_线段树+dfs序

    BZOJ_3252_攻略_线段树+dfs序 Description 题目简述:树版[k取方格数] 众所周知,桂木桂马是攻略之神,开启攻略之神模式后,他可以同时攻略k部游戏.今天他得到了一款新游戏< ...

  7. BZOJ_3729_Gty的游戏_博弈论+splay+dfs序

    BZOJ_3729_Gty的游戏_博弈论+splay+dfs序 Description 某一天gty在与他的妹子玩游戏. 妹子提出一个游戏,给定一棵有根树,每个节点有一些石子,每次可以将不多于L的石子 ...

  8. BZOJ_2821_作诗(Poetize)_分块

    BZOJ_2821_作诗(Poetize)_分块 Description 神犇SJY虐完HEOI之后给傻×LYD出了一题:SHY是T国的公主,平时的一大爱好是作诗.由于时间紧迫,SHY作完诗 之后还要 ...

  9. BZOJ_2434_[NOI2011]_阿狸的打字机_(AC自动机+dfs序+树状数组)

    描述 http://www.lydsy.com/JudgeOnline/problem.php?id=2434 给出\(n\)个字符串,\(m\)个询问,对于第\(i\)个询问,求第\(x_i\)个字 ...

随机推荐

  1. IOS常用第三方库《转》

    UI 动画 网络相关 Model 其他 数据库 缓存处理 PDF 图像浏览及处理 摄像照相视频音频处理 响应式框架 消息相关 版本新API的Demo 代码安全与密码 测试及调试 AppleWatch ...

  2. 用xml还是json

    1.定义介绍 (1).XML定义 扩展标记语言 (Extensible Markup Language, XML) ,用于标记电子文件使其具有结构性的标记语言,可以用来标记数据.定义数据类型,是一种允 ...

  3. Java 理论与实践: 并发集合类

    Java 理论与实践: 并发集合类 DougLea的 util.concurrent 包除了包含许多其他有用的并发构造块之外,还包含了一些主要集合类型 List 和 Map 的高性能的.线程安全的实现 ...

  4. Java杂记9—NIO

    前言 非阻塞IO,也被称之为新IO,它重新定义了一些概念. 缓冲buffer 通道 channel 通道选择器 BIO 阻塞IO,几乎所有的java程序员都会的字节流,字符流,输入流,输出流等分类就是 ...

  5. form表单序列化为Jquery对象

    <form id="DailyFinancial" > @*class="form-inline"*@ <div class="fo ...

  6. python笔记:#004#注释

    注释 目标 注释的作用 单行注释(行注释) 多行注释(块注释) 01. 注释的作用 使用用自己熟悉的语言,在程序中对某些代码进行标注说明,增强程序的可读性 02. 单行注释(行注释) 以 # 开头,# ...

  7. DOM4J熟知

    什么是解析xml 系统最终会从xml中读取数据. 读取的过程就是解析. CRUD ==> 增删改查 ==> create read update delete ==> 解析指的就是读 ...

  8. 转 Web用户的身份验证及WebApi权限验证流程的设计和实现

    前言:Web 用户的身份验证,及页面操作权限验证是B/S系统的基础功能,一个功能复杂的业务应用系统,通过角色授权来控制用户访问,本文通过Form认证,Mvc的Controller基类及Action的权 ...

  9. 对于 Netty ByteBuf 的零拷贝(Zero Copy) 的理解

    此文章已同步发布在我的 segmentfault 专栏. 根据 Wiki 对 Zero-copy 的定义: "Zero-copy" describes computer opera ...

  10. jmeter接口测试报java.net.SocketException: Socket closed错误。

    如题,jmeter报出java.net.SocketException: Socket closed,我查询了下,服务器是正常的,可以返回数据,基本确定问题出在我这边jmeter.查询原因,看到有人说 ...