Bookshop

这道题让我意识到我根本不会用树剖

参考题解 (感谢聂会

题目链接

题目大意

给出一棵 nnn 个结点的树,每个结点有一个价值为 wiw_iwi​ 的商品

mmm 次询问,每次问如果一个人带着 ccc 块钱,从 xxx 出发到达 yyy 结束,在路上遇到能买的东西就必须买,不能买就继续往前走,最后剩多少钱?(询问独立)

n,m≤105wi,c≤109n,m≤10^5 \, \, \, \, \, \, w_i,c≤10^9n,m≤105wi​,c≤109

思路

树上区间信息问题,下意识树剖线段树,然鹅这道题的下一个数状态会受到之前数的影响,没有办法做到区间合并,于是我就 gg 了

没有办法区间合并,但是可以按照模拟的思想,按一定顺序枚举点,到 iii 点的时候就把所有要经过 iii 点 的 起点或终点 的点 xxx 都进行 cx−wi(cx>=wi)c_x-w_i(c_x>=w_i)cx​−wi​(cx​>=wi​) ( 最终 cxc_xcx​ 为 ansansans )

显然 ,可以把问题分解成 x−>lcax->lcax−>lca (dfndfndfn 递减) 和 lca−>ylca->ylca−>y (dfndfndfn 递增) 来处理 , 这时候我们要解决枚举到 iii 点的时候,只有要经过它的起点和终点在我们的数据结构里,这时候 树剖 就大显身手了

比如解决 x−>lcax->lcax−>lca 时 : 按照 i=n→1i=n \rightarrow 1i=n→1 枚举 dfn[x]=idfn[x]=idfn[x]=i

这样树剖操作会把 x−>lcax->lcax−>lca 分解为 log(n)log(n)log(n) 个区间(树剖保证了每次向上跳的链是一个在 dfndfndfn序 上连续的一段) ,在每一个区间[l,R][l,R][l,R]中,LLL 点时把起点加入数据结构,再在 RRR 点删去,从而达到预期结果

实现

  1. 数据结构:维护不小于 kkk 的元素 减去 kkk
  • 无旋 treaptreaptreap 实现 : x≥2×kx\geq2 \times kx≥2×k 打 tagtagtag ,同时减去 kkk 不会影响他们之间的排名顺序,同时,其他元素小于 kkk , 相对排名也不影响

  • k≤x<2×kk \leq x<2 \times kk≤x<2×k 暴力修改 , 均摊 m×log(m)×log(k)m \times log(m) \times log(k)m×log(m)×log(k)

  1. 同时要访问 id[x]id[x]id[x]( xxx 在平衡树中的编号) 并支持删除和加入操作
  • 模仿 P5217 贫穷 跳fa[]fa[]fa[] 查出 rankrankrank 进行操作
  1. 哪些点经过区间左右端点??
  • 可以把问题离线,跳 LCALCALCA 时用 vectorvectorvector 放进每一次跳到的端点

Code

# define author XUAN
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+7;
template <typename T> inline void read(T &x)
{T ch=getchar(),xx=1;x=0;while(!isdigit(ch)) xx=ch=='-'?-1:xx,ch=getchar();while(isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();x*=xx;
}
template <typename T> void print(T x)
{if(x<0) putchar('-'),x=-x;if(x>9) print(x/10);putchar(x%10+'0');
}
//mt19937 myrand(20051024);
int m,d,n,fa[N],top[N],siz[N],to[N<<1],pre[N<<1],w[N],son[N],seg[N],dfn[N],tot,dep[N],h[N];
void add(int a,int b){++d;pre[d]=h[a];h[a]=d;to[d]=b;return;}
struct Que{int w,id; // (树上编号) Que(int _w=0,int _id=0){w=_w;id=_id;return;}
}q[N];
inline void dfs1(int x,int f){dep[x]=dep[f]+1;fa[x]=f;siz[x]=1;for(int i=h[x];i;i=pre[i]){int y=to[i];if(y==f) continue;dfs1(y,x);siz[x]+=siz[y];if(siz[y]>siz[son[x]]) son[x]=y; }return;
}
inline void dfs2(int x,int f){dfn[x]=++tot;seg[tot]=x;if(son[x]){top[son[x]]=top[x];dfs2(son[x],x);}for(int i=h[x];i;i=pre[i]){int y=to[i];if(y==f || y==son[x]) continue;top[y]=y;dfs2(y,x);}return;
}
vector <int> st[N],ed[N],St[N],Ed[N];
inline void LCA(int x,int y,int id){while(top[x]!=top[y]){if(dep[top[x]]>dep[top[y]]){st[dfn[x]].push_back(id);ed[dfn[top[x]]].push_back(id);x=fa[top[x]];}else{St[dfn[top[y]]].push_back(id);Ed[dfn[y]].push_back(id);y=fa[top[y]];}}if(dep[x]>=dep[y]) st[dfn[x]].push_back(id),ed[dfn[y]].push_back(id);else St[dfn[x]].push_back(id),Ed[dfn[y]].push_back(id);return;
}
class Treap{private :int rt;Que z[N];int top;# define lx tr[x].lc# define rx tr[x].rcstruct Node{int k,lc,rc,siz,fa,v,tag;Node(int _k=0,int _lc=0,int _rc=0,int _siz=0,int _fa=0,int _v=0,int _tag=0){k=_k;lc=_lc;rc=_rc;siz=_siz;fa=_fa;v=_v;tag=_tag;return;}void fix(int val){tag+=val;v+=val;return;}}tr[N];inline void pushup(int x){tr[x].fa=0;if(lx) tr[lx].fa=x;if(rx) tr[rx].fa=x;tr[x].siz=tr[lx].siz+tr[rx].siz+1;return;}inline void pushdown(int x){if(tr[x].tag==0) return;if(lx) tr[lx].fix(tr[x].tag);if(rx) tr[rx].fix(tr[x].tag);tr[x].tag=0;return;}inline int New(int id,int val){tr[id]=Node(rand(),0,0,1,0,val);return id;}inline void split(int x,int key,int &L,int &R){if(!x){L=R=0;return;}pushdown(x);if(tr[lx].siz<key) L=x,split(rx,key-tr[lx].siz-1,rx,R);else R=x,split(lx,key,L,lx);pushup(x);return;} inline int Find(int x){int ret=tr[lx].siz+1;while(x!=rt){int Fa= tr[x].fa;if(x==tr[Fa].rc) ret+=tr[tr[Fa].lc].siz+1;x=Fa;}return ret; }inline int Rank(int val){int x=rt,ret=0;while(x){pushdown(x);if(tr[x].v<val) ret+=tr[lx].siz+1,x=rx;else x=lx;}return ret+1;}inline int merge(int x,int y){if(!x || !y) return x|y;if(tr[x].k>tr[y].k){pushdown(x);rx=merge(rx,y);pushup(x);return x;}pushdown(y);tr[y].lc=merge(x,tr[y].lc);pushup(y);return y; }void DFS(int x){if(!x) return;pushdown(x);DFS(lx),DFS(rx);z[++top]=Que(tr[x].v,x);return;}public: inline void Clear(){rt=0;}inline void Fix(int val){if(!rt) return;int l=0,mid=0,r=0;int k=Rank(val);split(rt,k-1,l,r);rt=r;k=Rank(val+val);split(rt,k-1,mid,r);top=0;tr[r].fix(-val);DFS(mid);rt=l;for(int i=1;i<=top;++i) z[i].w-=val,ins(z[i]);   rt=merge(rt,r);return;}inline void ins(Que a){int l=0,r=0,k=a.w;k=Rank(k);split(rt,k-1,l,r);rt=merge(l,merge(New(a.id,a.w),r));return;}inline int del(Que a){int l=0,r=0,mid=0;int k=Find(a.id);split(rt,k-1,l,mid);split(mid,1,mid,r);rt=merge(l,r);return tr[mid].v;}
}T;
int main()
{int Case;read(Case);while(Case--){T.Clear();read(n);read(m);tot=0;for(int i=1;i<=n;++i){st[i].clear();ed[i].clear();St[i].clear();Ed[i].clear();h[i]=0,son[i]=0,read(w[i]);}d=0;for(int i=1;i<n;++i){int a,b;read(a),read(b);add(a,b),add(b,a);}top[1]=1;dfs1(1,0);dfs2(1,0);for(int i=1;i<=m;++i){int a,b;read(a),read(b),read(q[i].w);LCA(a,b,i);q[i].id=i;}for(int i=n;i;--i){ // upfor(int j=0;j<st[i].size();++j) T.ins(q[st[i][j]]);T.Fix(w[seg[i]]);for(int j=0;j<ed[i].size();++j) q[ed[i][j]].w=T.del(q[ed[i][j]]);}for(int i=1;i<=n;++i){ // downfor(int j=0;j<St[i].size();++j) T.ins(q[St[i][j]]);T.Fix(w[seg[i]]);for(int j=0;j<Ed[i].size();++j) q[Ed[i][j]].w=T.del(q[Ed[i][j]]);}for(int i=1;i<=m;++i) print(q[i].w),putchar('\n');}return 0;
}

【HDU 6973】Bookshop (树剖+平衡树)相关推荐

  1. 【HDU 6973】Bookshop 树剖+平衡树

    [HDU 6973]Bookshop 树剖+平衡树 [引言] ​ 平衡树的题做得比较少,难得补一次神题,记录一下供以后学习. [题意] ​ 给出一棵 nnn 个结点的树,每个结点有一个价值为 pip_ ...

  2. 多校第九场总结,树剖

    http://bestcoder.hdu.edu.cn/blog/ 02 官方题解 由于没有修改操作,一个显然的想法是离线处理所有问题 将询问拆成1-x,1-y,1-LCA(x,y),则处理的问题转化 ...

  3. BZOJ 4817: [Sdoi2017]树点涂色(LCT+树剖+线段树)

    题目描述 Bob有一棵 nn 个点的有根树,其中1号点是根节点.Bob在每个点上涂了颜色,并且每个点上的颜色不同. 定义一条路径的权值是:这条路径上的点(包括起点和终点)共有多少种不同的颜色. Bob ...

  4. [SDOI2011]染色 (线段树维护子段问题+树剖)

    题意: 给定一棵 n 个节点的无根树,共有 m 个操作,操作分为两种: 1.将节点 a 到节点 b 的路径上的所有点(包括 a 和 b)都染成颜色 c. 2.询问节点 a 到节点 b 的路径上的颜色段 ...

  5. SP10628 COT - Count on a tree (树剖+可持久化线段树)

    题意: 给定一个包含 N 个结点的树. 树节点从 1 到 N编号..每个节点有一个整数权值. 我们会要求您执行以下操作: u v k : 询问从节点 u 到 节点 v 的路径上的第k小的权值 输入 在 ...

  6. 洛谷P4216 [SCOI2015]情报传递(树剖+主席树)

    传送门 我们可以进行离线处理,把每一个情报员的权值设为它开始收集情报的时间 那么设询问的时间为$t$,就是问路径上有多少个情报员的权值小于等于$t-c-1$ 这个只要用主席树上树就可以解决了,顺便用树 ...

  7. 暑假集训8.10-网络流套树剖套线段树

    题目:dtoj2797旅行商 其实就是裸的网络流套树剖套线段树其实代码不难码 emmmmmm我决定草率的直接上代码,这可能是一条无营养的博客.... #include<bits/stdc++.h ...

  8. BZOJ4034 树上操作(树剖 线段树大模板)

    BZOJ4034 long long 是大坑点 貌似long long 跟int 乘起来会搞事情?... A了这题线段树和树剖的基础OK 嘛 重点过掉的还是线段树区间更新的lazy tag吧 #inc ...

  9. 一棵树的生成树有几颗_次小生成树(树剖,生成树)

    生成树的概念: 在一个无向图中,设顶点数为\(n\),取其中\(n-1\)条边并使所有点相连,所得到的一棵树即为生成树. 最小生成树: 如果还没有接触过生成树的同学,欢迎戳->最小生成树详解 次 ...

最新文章

  1. 『假如我是面试官』RabbitMQ我会这样问!
  2. C语言实现ternary search三分查找算法(附完整源码)
  3. IOS调用WCF提供的服务方法,但是方法的参数是WCF那边自定义的对象,这样有办法调用么,如果可以IOS应该怎么传参呢?请问有了解的么,...
  4. STL源码剖析 基本算法 < stl_algobase.h >
  5. 《信息安全系统设计基础》实验一 开发环境的熟悉
  6. PowerShell 中执行 dir /b /s
  7. MATLAB通信系统建模与仿真
  8. 抽象工厂模式类图及代码示例
  9. 最全Web前端面试题汇总 笔试题汇总 JavaScript HTML css
  10. 咳咳,好久没发博客了,我还活着。(ps:又要进入鸽王模式了)
  11. MySQL(进阶篇)
  12. js插件 excel在线编辑插件X-Spreadsheet
  13. QQ浏览器F12弹出新窗口问题
  14. JSP+SQL基于JSP的学生信息管理系统(源代码+论文+答辩PPT)
  15. 选型宝访谈:当超融合一体机,具备云计算的基因,将会怎样?
  16. 对极验geetest滑块验证码图片还原算法的研究
  17. 书法字帖 PDF转化为可打印PDF
  18. Vue3表单验证 单个验证 统一验证 自定验证
  19. Win10图片打开很慢如何改回Win7的图片查看器打开?
  20. 济南高新技术企业认定条件

热门文章

  1. 消除视频水印的软件有哪些?试试这几款去水印软件
  2. 深度学习入门——Mini-batch、Momentum与Adam算法
  3. ArcSDE连接PostgreSQL数据库
  4. Socket编程服务器和客户端【重要】
  5. 关于java字符串+加号的理解
  6. 使用KeyManager免费更换多域名SSL证书。
  7. 软件配置管理与CMM/CMMI-三库管理
  8. 软考-项目资源管理(十三)
  9. kafka 创建消费者报错 consumer zookeeper is not a recognized option
  10. 为什么会是植物神经紊乱 如何辨别