冲刺NOI2017 (20) 距离 (可持久化树链剖分)
来源:互联网 发布:淘宝店铺装修工具 编辑:程序博客网 时间:2024/05/29 08:00
题目大意
给定一棵
其中
数据范围:
题解
我们先抛开这道题不谈,讨论另一个问题:
.
距离和
- 对于一棵有
n 个节点带权的树,树上有m 个黑点。现在有q 个询问,对于每个询问应该回答点k 到树上所有黑点的距离之和。(n,m,q<=2∗105)
分析这个问题,这个问题的答案可以表示为所有的黑点到k点的距离之和,即可以表示为以下形式:
因为对于每一个询问都包含了所有的黑点,所以式子的第一部分可以在每次向树中添加黑点的时候,树剖查询黑点到根节点的距离,并累加统计起来预处理好。
对于式子的第二部分,因为只与
对于式子的第三部分,我们想要统计的是
那么,把所有的黑点加入后,每对于一个
所以每对一个k点进行询问,用以上的方法对答案式子的三部分进行统计相加即可,时间复杂度
.
回到正题
掌握了上述的前置技能之后,我们就可以运用一些奇技淫巧来解决这道题了。为了方便描述,我们把题目输入中给出的原树称作树1,原树关于
因为询问是针对树1的询问,所以我们应该从树1下手分析。每当我们在树1中选用一个点
由于每一个点的加入都相当于对树剖线段树进行多次修改,所以不能用树剖来维护,而每次查询都需要支持查询多个版本,考虑使用主席树来维护各个版本。
我们从根节点开始向下逐个插入,每在树1中以dfs序插入一个点,就相当于在树2中加入一个黑点,同时也相当于在其父亲的线段树版本上进行了一次修改,这个部分用主席树维护版本即可。每一个版本就相当于一个黑点的集合。
那么对于一个
代码
#include <cstdio>#include <iostream>//#include <ctime>#include <algorithm>using namespace std;const int STRSIZE=40000000;char in1[STRSIZE];char *in=in1, *tempend;void Input() { tempend=in+STRSIZE; fread(in,1,STRSIZE,stdin);}inline void scan(int &x) { char c=*(in++); while(!(c>='0' && c<='9')) c=*(in++); x=c-'0'; c=*(in++); while(c>='0' && c<='9') { x=x*10+c-'0'; c=*(in++); }}inline void scan(long long &x) { char c=*(in++); while(!(c>='0' && c<='9')) c=*(in++); x=c-'0'; c=*(in++); while(c>='0' && c<='9') { x=x*10+c-'0'; c=*(in++); }}const int maxn=int(2e5)+111;int type,n,q;int p[maxn];int head[maxn], TOT=0;struct Edge { int to,cost,next; Edge() {} Edge(const int &y,const int &co,const int &nx):to(y),cost(co),next(nx) {}}eage[maxn<<1];inline void Add_eage(const int &x,const int &y,const int &cost) { eage[TOT]=Edge(y,cost,head[x]), head[x]=TOT++; eage[TOT]=Edge(x,cost,head[y]), head[y]=TOT++;}void Read() { scan(type), scan(n), scan(q); register int i,x,y,z; for(i=1;i<=n;++i) head[i]=-1; for(i=2;i<=n;++i) { scan(x), scan(y), scan(z); Add_eage(x,y,z); } for(i=1;i<=n;++i) scan(p[i]); return;}int dep[maxn], siz[maxn], fa[maxn], son[maxn], pw[maxn];void dfs1(const int &u) { register int i,v; siz[u]=1, son[u]=0; for(i=head[u];~i;i=eage[i].next) if(eage[i].to!=fa[u]) { v=eage[i].to; fa[v]=u, dep[v]=dep[u]+1, pw[v]=eage[i].cost; dfs1(v); siz[u]+=siz[v]; if(siz[v]>siz[son[u]]) son[u]=v; }}int top[maxn], seq[maxn], id[maxn], ind;void dfs2(const int &u) { seq[id[u]=++ind]=u; if(u==son[fa[u]]) top[u]=top[fa[u]]; else top[u]=u; if(son[u]) dfs2(son[u]); register int i; for(i=head[u];~i;i=eage[i].next) if(eage[i].to!=fa[u] && eage[i].to!=son[u]) dfs2(eage[i].to); return;}#define ls(k) ((k)<<1)#define rs(k) (ls(k)|1)#define mid ((l+r)>>1)int val[maxn];long long org[maxn<<2];void org_Build(const int &k,const int &l,const int &r) { org[k]=0; if(l==r) { org[k]=val[l]; return; } org_Build(ls(k),l,mid); org_Build(rs(k),mid+1,r); org[k]=org[ls(k)]+org[rs(k)]; return;}long long org_Query(int k,int l,int r,int ql,int qr) { if(ql<=l && r<=qr) return org[k]; long long tmp=0; if(ql<=mid) tmp+=org_Query(ls(k),l,mid,ql,qr); if(qr> mid) tmp+=org_Query(rs(k),mid+1,r,ql,qr); return tmp;}long long orgtree_Query(register int u,register int v) { long long tmp=0; while(top[u]!=top[v]) { if(dep[top[u]]<dep[top[v]]) swap(u,v); tmp+=org_Query(1,1,n,id[top[u]],id[u]); u=fa[top[u]]; } if(dep[u]>dep[v]) swap(u,v); tmp+=org_Query(1,1,n,id[u],id[v]); return tmp;}int LCA(int u,int v) { while(top[u]!=top[v]) { if(dep[top[u]]<dep[top[v]]) swap(u,v); u=fa[top[u]]; } if(dep[u]>dep[v]) swap(u,v); return u;}void Spilt() { fa[1]=0, dep[1]=1; dfs1(1); dfs2(1); register int i; for(i=1;i<=n;++i) val[i]=pw[seq[i]]; org_Build(1,1,n); return;}struct Node { long long res; int add,ls,rs;}node[int(1e7)];int root[maxn];int tot=0;void Build(int &k,int l,int r) { k=++tot; node[k].res=node[k].add=node[k].ls=node[k].rs=0; if(l==r) return; Build(node[k].ls,l,mid); Build(node[k].rs,mid+1,r); return;}long long Modify(int &k,int ok,int pre,int l,int r,int ql,int qr) { if(!k) node[k=++tot]=node[pre]; long long cur=0; if(ql==l && r==qr) { ++node[k].add; node[k].res+=org[ok]; return org[ok]; } if(qr<=mid) { if(node[k].ls<k) node[k].ls=0; cur+=Modify(node[k].ls,ls(ok),node[pre].ls,l,mid,ql,qr); } else if(ql>mid) { if(node[k].rs<k) node[k].rs=0; cur+=Modify(node[k].rs,rs(ok),node[pre].rs,mid+1,r,ql,qr); } else { if(node[k].ls<k) node[k].ls=0; cur+=Modify(node[k].ls,ls(ok),node[pre].ls,l,mid,ql,mid); if(node[k].rs<k) node[k].rs=0; cur+=Modify(node[k].rs,rs(ok),node[pre].rs,mid+1,r,mid+1,qr); } node[k].res+=cur; return cur;}void tree_Modify(int x,int y,int u,int v) { while(top[u]!=top[v]) { if(dep[top[u]]<dep[top[v]]) swap(u,v); Modify(root[x],1,root[y],1,n,id[top[u]],id[u]); u=fa[top[u]]; } if(dep[u]>dep[v]) swap(u,v); Modify(root[x],1,root[y],1,n,id[u],id[v]); return;}#define mp make_pairtypedef pair<long long,long long> pll;pll Query(int k,int ok,int l,int r,int ql,int qr) { if(ql==l && r==qr) return mp(node[k].res,org[ok]); long long tmp1=0, tmp2=0; pll tmp; if(qr<=mid) { tmp=Query(node[k].ls,ls(ok),l,mid,ql,qr); tmp1+=tmp.first, tmp2+=tmp.second; } else if(ql>mid) { tmp=Query(node[k].rs,rs(ok),mid+1,r,ql,qr); tmp1+=tmp.first, tmp2+=tmp.second; } else { tmp=Query(node[k].ls,ls(ok),l,mid,ql,mid); tmp1+=tmp.first, tmp2+=tmp.second; tmp=Query(node[k].rs,rs(ok),mid+1,r,mid+1,qr); tmp1+=tmp.first, tmp2+=tmp.second; } return mp(tmp1+tmp2*node[k].add,tmp2);}long long tree_Query(int x,int u,int v) { long long tmp=0; while(top[u]!=top[v]) { if(dep[top[u]]<dep[top[v]]) swap(u,v); tmp+=Query(root[x],1,1,n,id[top[u]],id[u]).first; u=fa[top[u]]; } if(dep[u]>dep[v]) swap(u,v); tmp+=Query(root[x],1,1,n,id[u],id[v]).first; return tmp;}void dfs(int u) { register int i,v; for(i=head[u];~i;i=eage[i].next) if(eage[i].to!=fa[u]) { v=eage[i].to; tree_Modify(v,u,1,p[v]); dfs(v); }} void Init() { Build(root[0],1,n); tree_Modify(1,0,1,p[1]); dfs(1);}inline long long Getres(const int &x,const int &k) { return orgtree_Query(1,k)*dep[x]+Query(root[x],1,1,n,1,n).first-(tree_Query(x,1,k)<<1);}inline long long Getans(const int &l,const int &r,const int &k) { int lca=LCA(l,r); long long tmp=Getres(l,k)+Getres(r,k)-Getres(lca,k); if(fa[lca]) tmp-=Getres(fa[lca],k); return tmp;}void Solve() { register int i; long long l,r,k,last=0; for(i=1;i<=q;++i) { scan(l), scan(r), scan(k); l^=(type*last), r^=(type*last), k^=(type*last); printf("%lld\n",last=Getans(l,r,k)); } return;}int main() {#ifndef ONLINE_JUDGE freopen("dis.in","r",stdin); freopen("dis.out","w",stdout);#endif// double t1=clock(); Input(); Read(); Spilt(); Init(); Solve();// printf("%.3lfsec\n",(clock()-t1)/CLOCKS_PER_SEC); return 0;}
- 冲刺NOI2017 (20) 距离 (可持久化树链剖分)
- 冲刺NOI2017 (20) 苹果树 (矩阵树定理 容斥原理 Meet in middle)
- 冲刺NOI2017 (22) 养猫 (线性规划方程转网络流)
- 冲刺NOI2017 (24) A (后缀数组 回滚莫队)
- jzoj5043 【NOI2017模拟4.4】保持平衡 (可撤销贪心)
- 可持久化Treap(范浩强Treap)
- noi2017解题报告(部分)
- NOI2017酱油记(伪)
- bzoj 2653 middle 二分+ 可持久化数据结构(可持久化感悟)
- [BZOJ3166][Heoi2013]Alo(可持久化线段树+可持久化tire树)
- 可持久化并查集(三)——从动态到可持久化
- 【模板】可持久化数组(可持久化线段树/平衡树)
- 初来乍到,盼可持久
- 可持久化数据结构
- 可持久化数据结构
- 可持久化二项堆
- bzoj3489 -- 可持久化树套树
- bzoj3489,可持久化树套树
- Target runtime Apache Tomcat v7.0 is not defined.
- CRC循环冗余校验码
- PHP一致性Hash
- js 基础点(checkbox选中,时间大小,查询数组值,form重复提交)
- 订单提交后发送邮件
- 冲刺NOI2017 (20) 距离 (可持久化树链剖分)
- python/pip /conda 不是内部或外部的命令
- Code资格赛2
- 爆炸
- CST时间转换出现的误差问题
- 『pandas』pandas查漏补缺
- 基于树莓派的空气监测系统(3)PM2.5模块程序
- 解决ssd训练时出的问题
- CentOS安装FastDFS单节点分布式文件系统