[LNOI2014] LCA

匿名 (未验证) 提交于 2019-12-02 23:52:01

给定n个节点的有根树,q次询问,每次询问求$\sum _{l\leq i\leq r} dep[LCA(i,z)] $

˼·

根据wys巨神所说,如果不把dep这个约束去掉,那么将不容易用数据结构来维护,因为对于不同的i,\(dep[LCA]\)可能不一样

1.为了去掉dep,我们采取一种奇技淫巧,对于上面的一个 \(i\) ,将 \(root\)\(i\) 这条路径上的所有点权加一,那么\(dep[LCA]\)就可以通过查询\(root\)\(z\)这条路径上的点权和得到(WTF???

于是问题变成了链修改链查询,可以请出我们代码简短好写的树链剖分同学

然而我们不能对每个询问都暴力修改\(root\)\([l,r]\)这一些链,所以我们还需要一些小优化

2.离线处理,将每个询问拆成\([1,l-1]\)\([1,r]\)两份,那么这个询问可以用\(ans[1,r]-ans[1,l-1]\)得到,由于链修改操作与z无关(因为增加\(root\)\(i\)所以只与\(i\)有关),所以可以对所有询问的右端点排序,然后for一遍依次链修改即可

树链剖分模板题

由于有很多重复的操作(+代码过丑)所以去掉不必要的部分啦~~~

Code:

struct Q {     int r,z,opt;     ll ans;     bool operator < (const Q a)const     {         return r<a.r;     } }q[N<<1];int qsum=-1; bool cmp(Q a,Q b) {return a.opt<b.opt;} int main() {     read(n);read(m);     for(int i=1;i<n;++i)     {         int father; read(father);         add_edge(father+1,i+1);     }     for(int i=1;i<=m;++i)     {         int l,r,z;         read(l);read(r);read(z);         ++l;++r;++z;         q[++qsum].r=l-1; q[qsum].z=z; q[qsum].opt=qsum;         q[++qsum].r=r; q[qsum].z=z; q[qsum].opt=qsum;     }     sort(q,q+qsum+1);     seg[1]=rev[1]=top[1]=hfu=1;     dfs1(1);     dfs2(1);     int now=0;     for(int i=0;i<=qsum;++i)     {         while(now<q[i].r) modify_edge(1,++now,1);         q[i].ans=query_edge(1,q[i].z);     }     sort(q,q+qsum+1,cmp);     for(int i=1;i<=qsum;i+=2) printf("%lld\n",((q[i].ans-q[i-1].ans)%mod+mod)%mod);     return 0; }
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!