题目链接

题意

给出一棵边带权的树,多次在线询问一个点到一个区间内的点的距离和。

Sol

分块过不了的

一个 trick ,都知道要算两点之间距离可以拆成到根的距离和他们的 LCA 到根的距离 ,其实要算多个点到一个点距离也可以使用一个类似的 trick。

问题就在于快速求解所有的:$$\sum_{v\in S}deep[LCA(u,v)]$$

我们对于要询问的点集 \(S\) ,每一个点向上把所有反祖的边都覆盖一次,然后对于 \(u\) 点我们把它拿着一步步向上走,对于每一条经过的边把它被覆盖的次数与这条边的边权的积求和,最后就是上面那个式子了。

也就是说现在我们的问题是快速求出一个区间内所有点向上覆盖后某一个点向上的每条边被覆盖的次数与边权的积。

这个显然就用 主席树+树链剖分 来维护一下就可以了。

把点按顺序插入,每一个点在树上用树剖往上,每一段在内层线段树中进行修改。

不过这里是区间修改,直接打可下放标记可能会很伤空间 ,那么可以用标记永久化。

但是我们这里是区间询问,那么就要用到一些巧妙的方法。

这个方法也可以用于二维线段树等一般只适用于单点查询的问题。

观察我们的询问方式,先把我们要询问的区间分为 \(log\) 个区间,然后当当前区间被完全覆盖的时候我们为了保证复杂度肯定不能继续往下了,这样如果我们使用常规的标记永久化的话我们就有可能没办法计算到下面的点的答案了。

这样子我们就还需要维护一个标记,表示当前区间总修改量,即使当前区间没有被修改完全修改我们也要更新这个标记。

这样当我们查询到一个被询问区间完全覆盖的区间的时候我们就直接把当前区间的总修改量加上就可以了,因为我们只有当询问完全覆盖当前区间的时候才会用到这个标记,而这个标记相当于是把下面的修改信息都上传了之后的信息,就没有问题了。

code:

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. template<class T>inline void init(T&x){
  4. x=0;char ch=getchar();bool t=0;
  5. for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-')t=1;
  6. for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<1)+(x<<3)+(ch-48);
  7. if(t) x=-x;return;
  8. }
  9. const int N=1.5e5+10;
  10. int n,m,tp,RT;
  11. typedef long long ll;
  12. int dep[N],fa[N];ll dis[N];
  13. struct edge{
  14. int to,next,w;
  15. }a[N<<1];
  16. int LIM;int head[N],cnt=0;
  17. inline void add(int x,int y,int z){a[++cnt]=(edge){y,head[x],z};head[x]=cnt;}
  18. int id[N],dfn[N],size[N],top[N],son[N],I=0,Ret[N];
  19. namespace LISAN{
  20. int age[N],id[N];
  21. inline bool cmp(int i,int j){return age[i]<age[j];}
  22. inline int Lower(register int x){
  23. register int l=1,r=n,pos=n+1;
  24. while(l<=r){
  25. register int mid=l+r>>1;
  26. if(age[id[mid]]>=x) pos=mid,r=mid-1;else l=mid+1;
  27. }
  28. return pos;
  29. }
  30. void Prepare(){for(int i=1;i<=n;++i) id[i]=i,init(age[i]);sort(id+1,id+1+n,cmp);return;}
  31. }using LISAN::Lower;
  32. void Dfs(int u){
  33. size[u]=1;
  34. for(int v,i=head[u];i;i=a[i].next){
  35. v=a[i].to;if(v==fa[u]) continue;
  36. fa[v]=u,dep[v]=dep[u]+1;dis[v]=dis[u]+a[i].w;
  37. Ret[v]=a[i].w;Dfs(v);size[u]+=size[v];
  38. if(!son[u]||size[v]>size[son[u]]) son[u]=v;
  39. }
  40. return;
  41. }
  42. void dfs(int u,int t){
  43. top[u]=t;id[u]=++I,dfn[I]=u;
  44. if(!son[u]) return;
  45. dfs(son[u],t);
  46. for(int v,i=head[u];i;i=a[i].next) if((v=a[i].to)==son[u]||v==fa[u]) continue;else dfs(v,v);
  47. return;
  48. }
  49. ll Sum[N],SR[N];
  50. const int MAXN=N*100;
  51. int ls[MAXN],rs[MAXN],vis[MAXN],rt[N];
  52. ll E[MAXN];int F[MAXN];int cur=0,NOW=0;
  53. void Build(int &u,int l,int r){
  54. u=++cur;E[u]=F[u]=0;
  55. if(l==r) return;
  56. int mid=(l+r)>>1;
  57. Build(ls[u],l,mid);Build(rs[u],mid+1,r);
  58. return;
  59. }
  60. void Modify(int&u,int l,int r,int L,int R){
  61. if(L>R) return;
  62. int p=u;
  63. if(vis[p]!=NOW) {p=++cur;
  64. ls[p]=ls[u],rs[p]=rs[u];
  65. E[p]=E[u],F[p]=F[u];vis[p]=NOW;
  66. u=p;
  67. }E[p]+=SR[R]-SR[L-1];
  68. if(l>=L&&r<=R) {++F[p];return;}
  69. int mid=l+r>>1;
  70. if(mid>=R) return Modify(ls[p],l,mid,L,R);
  71. if(mid< L) return Modify(rs[p],mid+1,r,L,R);
  72. Modify(ls[p],l,mid,L,mid);Modify(rs[p],mid+1,r,mid+1,R);
  73. return;
  74. }
  75. inline void Modify(int &rt,int u){
  76. ++NOW;
  77. while(top[u]) {Modify(rt,1,n,id[top[u]],id[u]);u=fa[top[u]];}
  78. return;
  79. }
  80. void Query(int v,int u,int l,int r,int L,int R,ll&ans){
  81. if(L>R) return;
  82. if(!u&&!v) return;
  83. if(l>=L&&r<=R) {ans+=E[u]-E[v];return;}
  84. ans+=(SR[R]-SR[L-1])*(F[u]-F[v]);
  85. int mid=l+r>>1;
  86. if(mid>=R) return Query(ls[v],ls[u],l,mid,L,R,ans);
  87. if(mid< L) return Query(rs[v],rs[u],mid+1,r,L,R,ans);
  88. return Query(ls[v],ls[u],l,mid,L,mid,ans),Query(rs[v],rs[u],mid+1,r,mid+1,R,ans);
  89. }
  90. inline ll Query(int l,int r,int u){
  91. ll res=0;
  92. while(top[u]) Query(rt[l],rt[r],1,n,id[top[u]],id[u],res),u=fa[top[u]];
  93. return res;
  94. }
  95. void work(){
  96. int lst=0;
  97. Dfs(1),dfs(1,1);
  98. for(int i=1;i<=n;++i) SR[i]=SR[i-1]+Ret[dfn[i]];
  99. Build(rt[0],1,n);
  100. for(int i=1;i<=n;++i) Sum[i]=Sum[i-1]+dis[LISAN::id[i]],rt[i]=rt[i-1],Modify(rt[i],LISAN::id[i]);
  101. for(int i=1;i<=m;++i) {
  102. int l,r,x;init(x),init(l),init(r);
  103. l=(l+lst)%LIM,r=(r+lst)%LIM;
  104. if(l>r) swap(l,r);
  105. l=Lower(l);r=Lower(r+1)-1;ll ans=0;
  106. ans=Query(l-1,r,x);
  107. ans=(Sum[r]-Sum[l-1])+(ll)(r-l+1)*dis[x]-(ans<<1);
  108. printf("%lld\n",ans);
  109. lst=ans%LIM;
  110. }
  111. }
  112. int main()
  113. {
  114. init(n),init(m),init(LIM);
  115. LISAN::Prepare();
  116. int u,v,w;
  117. for(int i=1;i<n;++i) {init(u),init(v),init(w);add(u,v,w);add(v,u,w);}
  118. work();
  119. return 0;
  120. }

【LuoguP3241】[HNOI2015] 开店的更多相关文章

  1. [HNOI2015]开店 树链剖分,主席树

    [HNOI2015]开店 LG传送门 蒟蒻表示不会动态淀粉质. 先把点按年龄排序, 设\(dis[i]\)表示\(i\)到根的距离. 把我们要算的东西稍微变下形:\(ans\) \[ = \sum \ ...

  2. 洛谷 P3241 [HNOI2015]开店 解题报告

    P3241 [HNOI2015]开店 题目描述 风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到人生哲学.最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点钱. 这样的想法当然非 ...

  3. [BZOJ4012][HNOI2015]开店(动态点分治,树链剖分)

    4012: [HNOI2015]开店 Time Limit: 70 Sec  Memory Limit: 512 MBSubmit: 2168  Solved: 947[Submit][Status] ...

  4. 【BZOJ4012】[HNOI2015]开店 动态树分治+二分

    [BZOJ4012][HNOI2015]开店 Description 风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到人生哲学.最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点 ...

  5. BZOJ4012 [HNOI2015]开店

    Description 风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到 人生哲学.最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点钱.这样的 想法当然非常好啦,但是她们也发现 ...

  6. bzoj 4012: [HNOI2015]开店

    Description 风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到 人生哲学.最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点钱.这样的 想法当然非常好啦,但是她们也发现 ...

  7. bzoj 4012: [HNOI2015]开店 主席树

    Description 风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到 人生哲学.最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点钱.这样的 想法当然非常好啦,但是她们也发现 ...

  8. BZOJ4012[HNOI2015]开店——树链剖分+可持久化线段树/动态点分治+vector

    题目描述 风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到 人生哲学.最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点钱.这样的 想法当然非常好啦,但是她们也发现她们面临着一个 ...

  9. BZOJ4012: [HNOI2015]开店【动态点分治】

    Description 风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到 人生哲学.最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点钱.这样的 想法当然非常好啦,但是她们也发现 ...

随机推荐

  1. Linux_用户权限管理

    目录 目录 用户管理 useradd创建用户 userdel删除用户 usermod修改用户账号 passwd修改用户密码 用户权限设置 用户组管理 查看用户的属组 修改用户组gpasswd 为没有家 ...

  2. MYSQL常见安装错误集:[ERROR] --initialize specified but the data directory has files in it. Abort

    1.[ERROR] --initialize specified but the data directory has files in it. Abort [错误] -初始化指定,但数据目录中有文件 ...

  3. Django中Cookie和Session配置和操作

    Cookie Cookie以键值对Key-Value形势进行信息的存储. Cookie基于域名安全,不同域名的Cookie是不能互相访问的 Cookie是存储在浏览器中的一段纯文本信息,建议不要存储敏 ...

  4. Debian系统中当安装deb软件时出现:deb cdrom:[Debian GNU/Linux 9.3.0 _Stretch_ - Official amd64 DVD Binary-1 20171209-12:11]/ stretch contrib main

    vi /etc/apt/sources.list // 注释掉下面这句话# deb cdrom:[Debian GNU/Linux 9.3.0 _Stretch_ - Official amd64 D ...

  5. unity监听粒子播放结束

    需要在粒子上挂脚本 脚本添加代码 public void OnParticleSystemStopped() { Debug.Log("粒子停止"); } 这是个生命周期 粒子的 ...

  6. [JS] 鼠标点击文本框清空默认值,离开文本框恢复默认值

    在使用文本框的时候,若设定了初始值,选择文本框进行输入的时候要将本来的内容进行删除,会显得非常麻烦 可以在文本框属性定义触发onfocus和onblur两个事件时对应的js功能 下面以asp.net代 ...

  7. HTTP请求状态码为400时的原因

    2019-11-30 出现这个请求无效说明请求没有进入后台服务器里 原因: (1)前端提交的字段名称或者字段类型和后台的实体类不一样 或者前端提交的参数跟后台需要的参数个数不一致,导致无法封装 (2) ...

  8. [转帖]挖洞经验 | 获取Facebook Marketplace卖家精确地理位置信息

    挖洞经验 | 获取Facebook Marketplace卖家精确地理位置信息 https://www.freebuf.com/vuls/202820.html 知识就是力量 5000刀的一个漏洞. ...

  9. STM32 晶振 系统时钟8MHZ和72Mhz的原因

    首先问题描述: 1.自己画的板子和淘宝买的最小系统板 系统时钟不一致,自己画的是8Mhz,HSE失败:最小系统板72Mhz 2.最小系统板在程序1运行仿真的时候,查看peripherals->P ...

  10. mock.js的运用

    一:概念 Mock.js是一款模拟数据生成器,旨在帮助前端攻城师独立于后端进行开发,帮助编写单元测试.提供了以下模拟功能: 根据数据模板生成模拟数据 模拟 Ajax 请求,生成并返回模拟数据 基于 H ...