BZOJ 4012: [HNOI2015]开店
2016-04-13 19:51
405 查看
这叫啥?可持久化树链剖分?
首先忽略掉那个年龄的限制
那就是求所有点到某点的路径之和
这个画个图会发现是 Σdepth[i]+n*depth[u]-2*Σdepth(lca(u,i))
前两个可以O(1)求,最后那个可以用树剖求。
方法就是每个点到根的路径测度+1,这个可以用线段树更新,然后u到根的路径上的测度与长度之积的和就是答案了。
但是出现了那个可恶的限制
不过嘛,我们有传说中的chairman algorithm
于是我们把它变成两个前缀相减,再用可持久化线段树求前缀和
空间O(n(logn)^2),时间O(n(logn)^2)
(由于这题空间不是很好说,于是我把pushdown操作干掉了,每次往下找的时候把标记加起来,然后就上首页了,感觉跑得飞快啊)
首先忽略掉那个年龄的限制
那就是求所有点到某点的路径之和
这个画个图会发现是 Σdepth[i]+n*depth[u]-2*Σdepth(lca(u,i))
前两个可以O(1)求,最后那个可以用树剖求。
方法就是每个点到根的路径测度+1,这个可以用线段树更新,然后u到根的路径上的测度与长度之积的和就是答案了。
但是出现了那个可恶的限制
不过嘛,我们有传说中的chairman algorithm
于是我们把它变成两个前缀相减,再用可持久化线段树求前缀和
空间O(n(logn)^2),时间O(n(logn)^2)
(由于这题空间不是很好说,于是我把pushdown操作干掉了,每次往下找的时候把标记加起来,然后就上首页了,感觉跑得飞快啊)
#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> using namespace std; const int M=13000000; const int N=150000+5; typedef long long ll; struct Node{ int lc,rc,cov,ti; ll sum; }tr[M]; int tot; int dep ,top ,fa ,siz ,son ,pos ,rank ,cost ,depth ,sz; struct Edge{int to,next,v;}e[N<<1]; int head ,cnt; ll len(int l,int r){ return depth[rank[r]]-depth[fa[rank[l]]]; } void ins(int u,int v,int w){ e[++cnt]=(Edge){v,head[u],w};head[u]=cnt; } void dfs(int u){ siz[u]=1; for(int i=head[u];i;i=e[i].next){ int v=e[i].to;if(v==fa[u])continue; fa[v]=u;dep[v]=dep[u]+1;cost[v]=e[i].v;depth[v]=depth[u]+cost[v]; dfs(v); siz[u]+=siz[v];if(siz[v]>siz[son[u]])son[u]=v; } } void dfs(int u,int tp){ top[u]=tp;pos[u]=++sz;rank[sz]=u; if(son[u])dfs(son[u],tp); for(int i=head[u];i;i=e[i].next){ int v=e[i].to; if(v!=son[u]&&v!=fa[u])dfs(v,v); } } ll update(int &o,int l,int r,int a,int b,int ti){ if(tr[o].ti!=ti)tr[++tot]=tr[o],o=tot,tr[tot].ti=ti; if(l==a&&r==b){tr[o].cov++;tr[o].sum+=len(l,r);return len(l,r);} else{ int mid=l+r>>1; ll add=0; if(b<=mid)add+=update(tr[o].lc,l,mid,a,b,ti); else if(mid<a)add+=update(tr[o].rc,mid+1,r,a,b,ti); else add+=update(tr[o].lc,l,mid,a,mid,ti)+update(tr[o].rc,mid+1,r,mid+1,b,ti); tr[o].sum+=add; return add; } } ll query(int o,int l,int r,int a,int b,int cov){ if(l==a&&b==r)return tr[o].sum+len(l,r)*cov; else{ int mid=l+r>>1; cov+=tr[o].cov; if(b<=mid)return query(tr[o].lc,l,mid,a,b,cov); else if(mid<a)return query(tr[o].rc,mid+1,r,a,b,cov); else return query(tr[o].lc,l,mid,a,mid,cov)+query(tr[o].rc,mid+1,r,mid+1,b,cov); } } int root ; int n; void update(int u,int ti){ while(u){ update(root[ti],1,n,pos[top[u]],pos[u],ti); u=fa[top[u]]; } } ll query(int u,int ti){ ll ans=0; while(u){ ans+=query(root[ti],1,n,pos[top[u]],pos[u],0); u=fa[top[u]]; } return ans; } int hash ,id ,rk ; ll sum ; bool cmp(int i,int j){ return hash[i]<hash[j]; } int findl(int l,int r,int x){ while(l<=r){ int mid=l+r>>1; if(hash[id[mid]]<x)l=mid+1; else r=mid-1; } return l-1; } int findr(int l,int r,int x){ while(l<=r){ int mid=l+r>>1; if(hash[id[mid]]<=x)l=mid+1; else r=mid-1; } return l-1; } ll ask(int u,int ti){ return sum[ti]+(ll)ti*depth[u]-2*query(u,ti); } int main(){ //freopen("a.in","r",stdin); //freopen("a.out","w",stdout); int q,A;scanf("%d%d%d",&n,&q,&A); for(int i=1;i<=n;i++){ scanf("%d",&hash[i]); id[i]=i; } sort(id+1,id+1+n,cmp); for(int i=1;i<n;i++){ int u,v,w;scanf("%d%d%d",&u,&v,&w); ins(u,v,w);ins(v,u,w); } dfs(1);dfs(1,1); for(int i=1;i<=n;i++){ root[i]=root[i-1]; update(id[i],i); rk[id[i]]=i; sum[i]=sum[i-1]+depth[id[i]]; } ll ans=0; while(q--){ int u;ll a,b;scanf("%d%lld%lld",&u,&a,&b); int l=(a+ans)%A,r=(b+ans)%A; if(l>r)swap(l,r); l=findl(1,n,l);r=findr(1,n,r); ans=ask(u,r)-ask(u,l); printf("%lld\n",ans); } return 0; }这题好像能用动态点分治做哎,不过我比较懒(明明动态点分治更好写好吗)
相关文章推荐
- Python decorator 1: 函数
- Android中Parcelable接口的应用
- 简单的分页
- JavaScript 中实现继承的方式(列举3种在前一章,我们曾经讲解过创建类的最好方式是用构造函数定义属性,用原型定义方法。)
- bzoj 4421: [Cerc2015] Digit Division
- 制作网页---html拾遗
- lightoj 1275 - Internet Service Providers 一元二次方程
- matlab学习笔记 函数bsxfun repmat
- git 回滚到某次commit
- c++中虚函数的实现机制
- App性能测试前需要了解的内存原理
- activity劫持反劫持
- 常用SVN命令行
- 虚基类与虚拟继承
- CMSIS RTOS RTX License
- 观察者模式
- Java虚拟机(JVM)体系结构概述及各种性能参数优化总结
- EventBus3.0带你乐翻天
- redis启用持久化
- Nodejs控制权转移 next all