首先通过DFS序将原问题转化为序列上区间加、询问区间kth的问题。

考虑分块,设块大小为$K$,每块维护排序过后的$pair(值,编号)$。

对于修改,整块的部分可以直接打标记,而零碎的两块因为本来有序,故可以按照修改区间将其分离成两个有序序列$A$(不在修改区间)和$B$(在修改区间)。

对$B$每个值都加上一个常数,再与$A$归并排序,即可在$O(K)$的时间内修改零碎的两块。

对于查询,首先将零碎的两块用同样的方法分离出来,然后二分答案,在每个整块二分查找个数即可,时间复杂度$O(\frac{n}{K}\log^2n)$。

当$K$取$\sqrt{n}\log n$时取得最优复杂度$O(n\sqrt{n}\log n)$。

#include<cstdio>
#include<algorithm>
using namespace std;
typedef pair<int,int>P;
const int N=100010,K=12,M=(N>>K)+5,BUF=6000000;
char Buf[BUF],*buf=Buf;
int n,m,i,lim,op,x,y,g[N],w[N],nxt[N],stq[N],enq[N],dfn;
int block,st[M],en[M],tag[M];P a[N<<1];
inline void read(int&a){for(a=0;*buf<48;buf++);while(*buf>47)a=a*10+*buf++-48;}
inline void add(int x,int y,int z){w[y]=z;nxt[y]=g[x];g[x]=y;}
void dfs(int x,int y){
stq[x]=++dfn;
a[dfn]=P(y,dfn);
for(int i=g[x];i;i=nxt[i])dfs(i,y+w[i]);
enq[x]=dfn;
}
inline void change(int o,int l,int r,int p){
static P A[N],B[N];
int ca=0,cb=0,i,j,k=st[o];
for(i=st[o];i<=en[o];i++)if(a[i].second<l||a[i].second>r)A[++ca]=a[i];else B[++cb]=a[i],B[cb].first+=p;
i=j=1;
while(i<=ca&&j<=cb)a[k++]=A[i]<B[j]?A[i++]:B[j++];
while(i<=ca)a[k++]=A[i++];
while(j<=cb)a[k++]=B[j++];
}
inline void modify(int x,int y,int p){
int X=x>>K,Y=y>>K,i;
for(i=X+1;i<Y;i++)tag[i]+=p;
change(X,x,y,p);
if(X<Y)change(Y,x,y,p);
}
inline int ask(int o,int p){
int l=st[o],r=en[o],mid,t=l-1;
if(l>r)return 0;
p-=tag[o];
while(l<=r)if(a[mid=(l+r)>>1].first<=p)l=(t=mid)+1;else r=mid-1;
return t-st[o]+1;
}
inline int kth(int x,int y,int k){
if(k>y-x+1)return -1;
int X=x>>K,Y=y>>K,i,s=n+1,e=n;
tag[block+1]=tag[X];
for(i=st[X];i<=en[X];i++)if(a[i].second>=x&&a[i].second<=y)a[++e]=a[i];
st[block+1]=s,en[block+1]=e;
s=e+1;
if(X<Y){
tag[block+2]=tag[Y];
for(i=st[Y];i<=en[Y];i++)if(a[i].second<=y)a[++e]=a[i];
}
st[block+2]=s,en[block+2]=e;
int l=0,r=lim,mid,t,ans;
while(l<=r){
mid=(l+r)>>1;
t=ask(block+1,mid)+ask(block+2,mid);
for(i=X+1;i<Y&&t<k;i++)t+=ask(i,mid);
if(t>=k)r=(ans=mid)-1;else l=mid+1;
}
return ans;
}
int main(){
fread(Buf,1,BUF,stdin);read(n),read(m),read(x);
for(i=2;i<=n;i++)read(x),read(y),add(x,i,y),lim+=y;
dfs(1,0);
block=n>>K;
for(i=1;i<=n;i++)en[i>>K]=i;
for(i=n;i;i--)st[i>>K]=i;
for(i=0;i<=block;i++)sort(a+st[i],a+en[i]+1);
while(m--){
read(op),read(x),read(y);
if(op==1)printf("%d\n",kth(stq[x],enq[x],y));else modify(stq[x],enq[x],y),lim+=y;
}
return 0;
}

  

BZOJ4867 : [Ynoi2017]舌尖上的由乃的更多相关文章

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

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

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

    BZOJ_4867_[Ynoi2017]舌尖上的由乃_分块+dfs序 Description 由乃为了吃到最传统最纯净的美食,决定亲自开垦一片菜园.现有一片空地,由乃已经规划n个地点准备种上蔬菜.最新 ...

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

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

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

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

  5. 舌尖上的javascript数组和字符串基本操作

    Javascript数组基本操作 Javascript中的数组是一种特殊的对象,用来表示偏移量的索引是该对象的属性,索引可能是整数,然而这些数字索引在内部被转换为字符串类型,这是因为javascrip ...

  6. python基础-文件操作

    一.文件操作 打开文件时,需要指定文件路径和以何等方式打开文件,打开后,即可获取该文件句柄,日后通过此文件句柄对该文件操作. 打开文件的模式有: r ,只读模式[默认模式,文件必须存在,不存在则抛出异 ...

  7. Python之路,Day3 - Python基础3

    一.文件操作 对文件操作流程 打开文件,得到文件句柄并赋值给一个变量 通过句柄对文件进行操作 关闭文件 现有文件如下 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 ...

  8. Python之路第一课Day3--随堂笔记(文件操作)

    一.集合的介绍 1.集合操作 集合是一个无序的,不重复的数据组合,它的主要作用如下: 去重,把一个列表变成集合,就自动去重了 关系测试,测试两组数据之前的交集.差集.并集等关系 常用操作 s = se ...

  9. Python之路第一课Day2--随堂笔记

    入门知识拾遗 一.bytes类型 bytes转二进制然后转回来 msg="张杨" print(msg) print(msg.encode("utf-8")) p ...

随机推荐

  1. Python算法之二分查找法

    1: l = [2,3,5,10,15,16,18,22,26,30,32,35,41,42,43,55,56,66,67,69,72,76,82,83,88] 从列表中找到某个num的位置 def ...

  2. 20165206 实验一 Java开发环境的熟悉

    20165206 实验一 Java开发环境的熟悉 一.实验内容及步骤 实验一 Java开发环境的熟悉-1 建立有自己学号的实验目录. 通过vim Hello.java编辑代码. 编译.运行Hello. ...

  3. tensorflow实现RNN及Word2Vec

    参考:<tensorflow实战> 首先介绍一下Word2Vec Word2Vec:从原始语料中学习字词空间向量的预测模型.主要分为CBOW(Continue Bags of Words) ...

  4. 社会单位消防安全户籍化管理系统——半自动提交V1.0版本

    社会单位消防安全户籍化管理系统——半自动提交V1.0版本 首先先上代码,开发这个小程序其实是用来帮助同事完成一项每天都做的繁琐事件,以往需要花费十分钟做这件事情,现在就是傻瓜式,点几下鼠标就好了.本来 ...

  5. 山寨版 WP8.1 Cortana 启动 PC

    8.1 dev preview 发布以来 Cortana 很受关注 前一段看到有视频演示用 Cortana 来启动 PC 看视频也是启动第三方应用实现的,简单来弄其实就是个语音启动应用 + 网络唤醒么 ...

  6. [Bjoi2018]二进制

    题解: 首先发现性质 只有1个1的区间 或者 奇数个1且0的个数少于2这个区间是不合法的 然后这个东西暴力是比较好处理的 刚开始写的比较傻逼,分几种情况 先把0,1缩在一起 1.k1个0+1+k2个0 ...

  7. Codeforces 886E Maximum Element 组合数学 + dp

    我们定义dp[ i ]表示长度为 i 的序列, 最后没有一个==k的时候返回的方案数, 也就是最后强制返回 i 的方案数. 我们能得到dp方程   dp[ i ] = sum(dp[ i - j - ...

  8. ansible Invetory(管理主机信息)

    1. 定义组机和组 inventory文件可以是许多格式之一,具体取决于您拥有的inventory插件. 对于这个例子, /etc/ansible/hosts的格式是一个INI(类似于Ansible的 ...

  9. git之一: git基础

    参考: SourceTree使用 git教程 廖学风git  文档1 文档2 1. git 概念介绍 工作区: 就是你在电脑里能看到的目录,比如我的learngit文件夹就是一个工作区,工作区下面有. ...

  10. 2018牛客网暑假ACM多校训练赛(第七场)I Tree Subset Diameter 动态规划 长链剖分 线段树

    原文链接https://www.cnblogs.com/zhouzhendong/p/NowCoder-2018-Summer-Round7-I.html 题目传送门 -  https://www.n ...