【HNOI2015】开店
来源:互联网 发布:移动硬盘mac不显示 编辑:程序博客网 时间:2024/03/29 18:29
题目大意
给出一棵有n个节点的树,每条边有个边长,每个节点有个权值a[i],有q个询问形如”u l r”询问点u到所有权值在l到r之间的点的路径长度和
一眼解法
一个点与多个点之间的距离和,显然我们可以用点分治来做,对于每个分治中心,我们将其所有该层的点都记录下来,那么每层共有n个,最多
询问时我们就直接在重心树上跳,沿途记录答案就好了。
贴代码:
#include<cstring>#include<cstdio>#include<algorithm>#include<cmath>#include<iostream>#define fo(i,a,b) for(int i=a;i<=b;i++)#define fd(i,a,b) for(int i=a;i>=b;i--)using namespace std;typedef long long LL;typedef double db;const int N = 150010;int n,Q,A;int v[N];int fa[N],q[N],m,s[N],vis[N],tim,mv[N];bool bz[N];int f[N];struct point{ int x,v; LL s;}a[N*20];int r[N],k,l[N];int ce[N],rt[N*2],u,rmq[N*2][20],fir[N];LL dis[N];int h[N],tot;struct edge{ int x,len,next;}e[N*2];int get(){ char ch; int s=0; while(ch=getchar(),ch<'0'||ch>'9'); s=ch-'0'; while(ch=getchar(),ch>='0'&&ch<='9')s=s*10+ch-'0'; return s;}void inse(int x,int y,int z){ e[++tot].x=y; e[tot].len=z; e[tot].next=h[x]; h[x]=tot;}void dfs(int x){ rt[fir[x]=++u]=x; for(int p=h[x];p;p=e[p].next) if (!fir[e[p].x]){ ce[e[p].x]=ce[x]+1; dis[e[p].x]=dis[x]+e[p].len; dfs(e[p].x); rt[++u]=x; }}void getrmq(){ fo(i,1,u)rmq[i][0]=rt[i]; fo(j,1,log(u)/log(2)) fo(i,1,u-(1<<j)+1) if (ce[rmq[i][j-1]]<ce[rmq[i+(1<<(j-1))][j-1]])rmq[i][j]=rmq[i][j-1]; else rmq[i][j]=rmq[i+(1<<(j-1))][j-1];}LL getdis(int x,int y){ if (!x||!y)return 0; LL ans=dis[x]+dis[y]; x=fir[x],y=fir[y]; if (x>y)swap(x,y); int t=log(y-x+1)/log(2); if (ce[rmq[x][t]]<ce[rmq[y-(1<<t)+1][t]])return ans-2*dis[rmq[x][t]]; return ans-2*dis[rmq[y-(1<<t)+1][t]];}bool cmp(point x,point y){ return x.v<y.v;}void bfs(int x){ vis[q[m=1]=x]=++tim; s[x]=1; mv[x]=0; int head=0; while(head<m){ x=q[++head]; for(int p=h[x];p;p=e[p].next) if (!bz[e[p].x]&&vis[e[p].x]<tim){ vis[q[++m]=e[p].x]=tim; fa[e[p].x]=x; s[e[p].x]=1; mv[e[p].x]=0; } }}int solve(int x,int last){ bfs(x); int w=0; fd(i,m,1){ x=q[i]; s[fa[x]]+=s[x]; mv[fa[x]]=max(mv[fa[x]],s[x]); mv[x]=max(mv[x],m-s[x]); if (mv[x]*2<=m)w=x; } bz[w]=1; l[w]=k; r[w]=k+m; fo(i,1,m){ a[++k].x=q[i]; a[k].v=v[q[i]]; } sort(a+l[w]+1,a+r[w]+1,cmp); fo(i,l[w]+1,l[w]+m){ x=a[i].x; if (last)a[i].s=getdis(last,x); a[i].s=getdis(w,x)-a[i].s; if (i>l[w]+1)a[i].s=a[i].s+a[i-1].s; } for(int p=h[w];p;p=e[p].next) if (!bz[e[p].x])f[solve(e[p].x,w)]=w; return w;}int getw(int d,int u,int v){ int w=u+1,l=d,r=u; while(l<=r){ int mid=(l+r)/2; if (a[mid].v<v)l=mid+1; else{ r=mid-1; w=mid; } } return w;}LL getans(int L,int R,int u){ int x=u,ls=0; LL ans=0; while(x){ int w1=getw(l[x]+1,r[x],L),w2=getw(l[x]+1,r[x],R+1)-1; LL v=a[w1-1].s; if (w1==l[x]+1)v=0; if (w2>=w1)ans+=a[w2].s-v+LL(w2-w1+1-ls)*getdis(x,u); ls=max(0,w2-w1+1); x=f[x]; } return ans;}int main(){ freopen("shop.in","r",stdin); freopen("shop.out","w",stdout); n=get(),Q=get(),A=get(); fo(i,1,n)v[i]=get(); fo(i,1,n-1){ int x=get(),y=get(),z=get(); inse(x,y,z); inse(y,x,z); } dfs(ce[1]=1); getrmq(); solve(1,0); LL ans=0; fo(i,1,Q){ int u=get(); int a=get(),b=get(); int L=min((a+ans)%A,(b+ans)%A),R=max((a+ans)%A,(b+ans)%A); printf("%lld\n",ans=getans(L,R,u)); } fclose(stdin); fclose(stdout); return 0;}
0 0
- 【HNOI2015】开店
- HNOI2015 开店
- HNOI2015开店
- 【HNOI2015】开店
- bzoj4012: [HNOI2015]开店
- bzoj4012: [HNOI2015]开店
- BZOJ 4012: [HNOI2015]开店
- 【HNOI2015】开店(shop)
- [HNOI2015][JZOJ4068]开店
- BZOJ4012: [HNOI2015]开店
- 4012: [HNOI2015]开店
- BZOJ 4012 [HNOI2015]开店
- bzoj 4012 [HNOI2015]开店 【树链剖分】
- 【动态树分治】【bzoj 4012】: [HNOI2015]开店
- [动态树分治] BZOJ4012 [HNOI2015]开店
- BZOJ 4012: [HNOI2015]开店 -- 动态树分治
- [BZOJ4012][HNOI2015]开店-树链剖分-主席树
- BZOJ 4012 HNOI2015 开店 动态树分治+二分
- LeetCode344
- 腾飞之势,搏击苍穹:网页设计
- 数据结构学习之双向循环链表操作
- kafka集群配置启动及编程
- mysql性能调优(一):join查询(1)
- 【HNOI2015】开店
- 350. Intersection of Two Arrays II
- 程序语言设计3day EOF
- Android实现引导页并滑动跳转到主界面
- LeetCode 202. Happy Number & 263. Ugly Number
- java中JSP惯用200多个的脚本
- Activity启动方式的总结(3)
- HeadFirstJava——6_Java API
- 管道用于进程通信的实现