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时能过。
 
代码:
  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <algorithm>
  4. #include <math.h>
  5. using namespace std;
  6. #define RR register
  7. inline char nc() {
  8. static char buf[100000],*p1,*p2;
  9. return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
  10. }
  11. inline int rd() {
  12. RR int x=0;RR char s=nc();
  13. while(s<'0'||s>'9') s=nc();
  14. while(s>='0'&&s<='9') x=(x<<3)+(x<<1)+s-'0',s=nc();
  15. return x;
  16. }
  17. #define N 100500
  18. 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;
  19. struct A {
  20. int v,id;
  21. }a[N],b[N],c[N];
  22. inline bool cmp1(const A &x,const A &y) {
  23. return x.v<y.v;
  24. }
  25. inline void add(int u,int v,int w) {
  26. to[++cnt]=v; nxt[cnt]=head[u]; head[u]=cnt; val[cnt]=w;
  27. }
  28. void dfs(int x) {
  29. RR int i; dfn[x]=++tot; a[tot].v=dis[x]; a[tot].id=tot;
  30. for(i=head[x];i;i=nxt[i]) {
  31. dis[to[i]]=dis[x]+val[i];
  32. dfs(to[i]);
  33. }
  34. son[x]=tot;
  35. }
  36. inline void update(int l,int r,int v) {
  37. RR int p=pos[l],q=pos[r],i,j,k;
  38. RR int lb=0,lc=0;
  39. if(p==q) {
  40. for(i=L[p];i<=R[p];i++) {
  41. if(a[i].id<=r&&a[i].id>=l) b[++lb]=a[i],b[lb].v+=v;
  42. else c[++lc]=a[i];
  43. }
  44. i=1; j=1; k=L[p];
  45. while(i<=lb&&j<=lc) {
  46. if(b[i].v<=c[j].v) a[k++]=b[i++];
  47. else a[k++]=c[j++];
  48. }
  49. while(i<=lb) a[k++]=b[i++];
  50. while(j<=lc) a[k++]=c[j++];
  51. }else {
  52. for(i=p+1;i<q;i++) more[i]+=v;
  53.  
  54. lb=0,lc=0;
  55. for(i=L[p];i<=R[p];i++) {
  56. if(a[i].id>=l) b[++lb]=a[i],b[lb].v+=v;
  57. else c[++lc]=a[i];
  58. }
  59. i=1; j=1; k=L[p];
  60. while(i<=lb&&j<=lc) {
  61. if(b[i].v<=c[j].v) a[k++]=b[i++];
  62. else a[k++]=c[j++];
  63. }
  64. while(i<=lb) a[k++]=b[i++];
  65. while(j<=lc) a[k++]=c[j++];
  66.  
  67. lb=0; lc=0;
  68. for(i=L[q];i<=R[q];i++) {
  69. if(a[i].id<=r) b[++lb]=a[i],b[lb].v+=v;
  70. else c[++lc]=a[i];
  71. }
  72. i=1; j=1; k=L[q];
  73. while(i<=lb&&j<=lc) {
  74. if(b[i].v<=c[j].v) a[k++]=b[i++];
  75. else a[k++]=c[j++];
  76. }
  77. while(i<=lb) a[k++]=b[i++];
  78. while(j<=lc) a[k++]=c[j++];
  79. }
  80. }
  81. inline int search(int l,int r,int x) {
  82. RR int tmp=l,p=pos[l]; r++;
  83. x-=more[p];
  84. while(l<r) {
  85. int mid=(l+r)>>1;
  86. if(a[mid].v<=x) l=mid+1;
  87. else r=mid;
  88. }
  89. return l-tmp;
  90. }
  91. inline int findt(int x) {
  92. RR int l=1,r=t[0]+1,mid;
  93. while(l<r) {
  94. mid=(l+r)>>1;
  95. if(t[mid]<=x) l=mid+1;
  96. else r=mid;
  97. }
  98. return l-1;
  99. }
  100. inline int query(int x,int y,int k) {
  101. if(y-x+1<k) return -1;
  102. RR int p=pos[x],q=pos[y],i,j;
  103. if(p==q) {
  104. t[0]=0;
  105. for(i=L[p];i<=R[p];i++) {
  106. if(a[i].id>=x&&a[i].id<=y) t[++t[0]]=a[i].v+more[p];
  107. }
  108. }else {
  109. t[0]=0;
  110. RR int lb=0,lc=0;
  111. for(i=L[p];i<=R[p];i++) {
  112. if(a[i].id>=x) b[++lb]=a[i],b[lb].v+=more[p];
  113. }
  114. for(i=L[q];i<=R[q];i++) {
  115. if(a[i].id<=y) c[++lc]=a[i],c[lc].v+=more[q];
  116. }
  117. i=1; j=1;
  118. while(i<=lb&&j<=lc) {
  119. if(b[i].v<=c[j].v) t[++t[0]]=b[i++].v;
  120. else t[++t[0]]=c[j++].v;
  121. }
  122. while(i<=lb) t[++t[0]]=b[i++].v;
  123. while(j<=lc) t[++t[0]]=c[j++].v;
  124. }
  125. RR int l=0,r=mx+1,mid,re;
  126. while(l<r) {
  127. mid=(l+r)>>1; re=0;
  128. if(t[0]) re+=findt(mid);
  129. for(i=p+1;i<q;i++) re+=search(L[i],R[i],mid);
  130. if(re>=k) r=mid;
  131. else l=mid+1;
  132. }
  133. return l;
  134. }
  135. int main() {
  136. //freopen("a.in","r",stdin);
  137. //freopen("a.out","w",stdout);
  138. RR int kitty,opt;
  139. n=rd(); m=rd(); kitty=rd();
  140. RR int i,x,y,j;
  141. // int ln=n,lg=1;
  142. // while(ln) lg++,ln>>=1;
  143. for(i=2;i<=n;i++) {
  144. x=rd(); y=rd(); add(x,i,y);
  145. }
  146. // size=((int)ceil(sqrt(n)))*(lg);
  147. // printf("%d\n",size);return 0;
  148. size=3700;
  149. dfs(1);
  150. block=n/size;
  151. for(i=1;i<=block;i++) {
  152. L[i]=R[i-1]+1; R[i]=i*size;
  153. sort(a+L[i],a+R[i]+1,cmp1);
  154. mx=max(mx,a[R[i]].v);
  155. for(j=L[i];j<=R[i];j++) pos[j]=i;
  156. }
  157. if(R[block]!=n) {
  158. block++; L[block]=R[block-1]+1; R[block]=n;
  159. sort(a+L[block],a+n+1,cmp1);
  160. for(i=L[block];i<=n;i++) pos[i]=block;
  161. mx=max(mx,a[n].v);
  162. }
  163. while(m--) {
  164. opt=rd(); x=rd(); y=rd();
  165. if(opt==1) {
  166. printf("%d\n",query(dfn[x],son[x],y));
  167. }else {
  168. update(dfn[x],son[x],y); mx+=y;
  169. }
  170. }
  171. return 0;
  172. }

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. dll附加依赖项查看——dumpbin 命令

    VS自带工具   查看程序或动态链接库需要的动态链接库 dumpbin /dependents d:\test.exe 查看动态链接库的输出函数 dumpbin /exports d:\libmysq ...

  2. POSTGRESQL 并发控制

    http://meidayhxp.blog.163.com/blog/static/117608156201210243837491/ 这个内容是官方Doc中的一章,具体是那一版的,还未确认. 第九章 ...

  3. python3学习笔记4---引用http://python3-cookbook.readthedocs.io/zh_CN/latest/

    2018-03-01数据结构与算法(4) 1.16过滤序列元素 最简单的过滤序列元素的方法就是使用列表推导.比如: >>> mylist = [1, 4, -5, 10, -7, 2 ...

  4. eBay账号token授权

    1.注册开发者账号(https://go.developer.ebay.com/) hufangyong   hu6253859. 2.注册沙箱测试账号(http://sandbox.ebay.com ...

  5. Heap

    #include using namespace std; int heap[100010],cnt=0; void put(int x) { cnt++; heap[cnt]=x; int now= ...

  6. Java开源生鲜电商平台-系统架构与技术选型(源码可下载)

    Java开源生鲜电商平台-系统架构与技术选型(源码可下载) 1.  硬件环境 公司服务器 2.   软件环境 2.1  操作系统 Linux CentOS 6.8系列 2.2 反向代理/web服务器 ...

  7. ArrayList源码分析超详细

    ArrayList源码分析超详解 想要分析下源码是件好事,但是如何去进行分析呢?以我的例子来说,我进行源码分析的过程如下几步: 找到类:利用 IDEA 找到所需要分析的类(ztrl+N查找ArraLi ...

  8. 基于DP的矩阵连乘问题

    当多个连续可乘矩阵做乘法时,选择正确的做乘顺序可以有效减少做乘法的次数,而选择的方法可以很容易的通过DP实现. 原理就是对于每一个所求矩阵,搜索所有可以相乘得到它的方法,比较它们的消耗,选取最小值作为 ...

  9. js中几种实用的跨域方法原理详解【转】

    源地址:http://www.cnblogs.com/2050/p/3191744.html 这里说的js跨域是指通过js在不同的域之间进行数据传输或通信,比如用ajax向一个不同的域请求数据,或者通 ...

  10. IDEA安装教程

    1.下载安装程序A,链接:https://pan.baidu.com/s/1IAsGDbApfyNsHuS7_m0rdw 密码:fthp 2.下载一个配置程序B,下载安装之后,暂时不用管,之后会用到. ...