bzoj 3924: [Zjoi2015]幻想乡战略游戏 动态树分治
来源:互联网 发布:mdict for mac 编辑:程序博客网 时间:2024/05/16 08:33
题意
给出一棵树,边有边权。每次操作要求修改一个点的点权d,然后求一个点p使得
n,q<=100000
分析
实际上也就是动态维护整棵树的带权重心。
考虑先建出分治树,每个点维护三个值sd[x]表示该点子树内的点权和,sv[x]表示该点子树内所有点到该点的带权距离,tofa[x]表示该点子树内所有点到其父亲的带权距离。这里的子树和父亲都是指分治树上的。
修改的话就暴力沿着父亲往上跳,修改路径上的值即可。
查询的话,网上有很多题解说的都是从分治树的根节点开始一直往子树走,每次都要换根然后再复原。蒟蒻表示看的瑟瑟发抖一脸懵逼。
恩实际上我们可以首先找到带权重心,然后把带权重心到分治树的根的路径跑一遍就可以得到答案了。至于具体怎么求就自己yy好啦。
那我们怎么求带权重心呢?
首先我们把原树看做有根树,然后用dfs序+树状数组来维护每个点在原树中的子树内点权和。
然后我们从树分治的根节点开始,每次枚举该节点在原树中的所有出边,如果沿着这条边走更优的话,就从该节点走到该边在分治树中所属的子树内。
这样的复杂度严格来讲是O(nlog2)的,但实际跑的飞快,估计是树状数组常数小的缘故。
代码
#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<algorithm>#include<cmath>using namespace std;typedef long long LL;const int N=100005;int n,q,cnt,last[N],root,a1,a[N*2],dep[N],pos[N],sd[N],ls[N],lg[N*2],rmq[N*2][25],size[N],mx[N],tot,fa[N],sum,c[N],dfn[N],tim,mndfn[N],mxdfn[N];LL sv[N],tofa[N];struct edge{int to,len,next,to1;}e[N*3];bool vis[N];int read(){ int x=0,f=1;char ch=getchar(); while (ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f;}void addedge(int u,int v,int len){ e[++cnt].to=v;e[cnt].len=len;e[cnt].next=last[u];last[u]=cnt; e[++cnt].to=u;e[cnt].len=len;e[cnt].next=last[v];last[v]=cnt;}void addedge1(int u,int v,int len){ e[++cnt].to=v;e[cnt].len=len;e[cnt].next=ls[u];ls[u]=cnt;}void dfs(int x,int fa){ pos[x]=++a1;a[a1]=dep[x];dfn[++tim]=x;mndfn[x]=mxdfn[x]=tim; for (int i=last[x];i;i=e[i].next) { if (e[i].to==fa) continue; dep[e[i].to]=dep[x]+e[i].len; dfs(e[i].to,x); a[++a1]=dep[x]; } mxdfn[x]=tim;}void ins(int x,int y){ while (x<=n) c[x]+=y,x+=x&(-x);}int get_w(int x){ int l=mndfn[x]-1,r=mxdfn[x]; int ans=0; while (r) ans+=c[r],r-=r&(-r); while (l) ans-=c[l],l-=l&(-l); return ans;}int get_len(int x,int y){ int l=pos[x],r=pos[y]; if (l>r) swap(l,r); int w=lg[r-l+1]; return dep[x]+dep[y]-2*min(rmq[l][w],rmq[r-(1<<w)+1][w]);}void get_root(int x,int fa){ size[x]=1;mx[x]=0; for (int i=last[x];i;i=e[i].next) { if (e[i].to==fa||vis[e[i].to]) continue; get_root(e[i].to,x); size[x]+=size[e[i].to]; mx[x]=max(mx[x],size[e[i].to]); } mx[x]=max(mx[x],tot-size[x]); if (!root||mx[x]<mx[root]) root=x;}void build(int x){ vis[x]=1; for (int i=last[x];i;i=e[i].next) { if (vis[e[i].to]) continue; root=0;tot=size[e[i].to]; get_root(e[i].to,x); e[i].to1=root; fa[root]=x;addedge1(x,root,get_len(x,root)); build(root); }}void modify(int x,int y,int z){ sd[x]+=z;sv[x]+=(LL)z*get_len(x,y); if (!fa[x]) return; tofa[x]+=(LL)z*get_len(y,fa[x]); modify(fa[x],y,z);}int find(int x){ for (int i=last[x];i;i=e[i].next) { int w; if (dep[e[i].to]>dep[x]) w=get_w(e[i].to); else w=sum-get_w(x); if (w*2>sum) return find(e[i].to1); } return x;}LL query(int x,int y,int son){ if (!x) return 0; LL ans=0; if (x==y) ans=sv[x]; else ans=sv[x]-tofa[son]+(LL)get_len(x,y)*(sd[x]-sd[son]); return ans+query(fa[x],y,x);}int main(){ n=read();q=read(); for (int i=1;i<n;i++) { int x=read(),y=read(),z=read(); addedge(x,y,z); } dfs(1,0); for (int i=1;i<=a1;i++) lg[i]=log(i)/log(2),rmq[i][0]=a[i]; for (int j=1;j<=lg[a1];j++) for (int i=1;i<=a1-(1<<j)+1;i++) rmq[i][j]=min(rmq[i][j-1],rmq[i+(1<<(j-1))][j-1]); root=0;tot=n; get_root(1,0); int R=root; build(root); while (q--) { int x=read(),y=read();sum+=y; modify(x,x,y); ins(mndfn[x],y); int ansp=find(R); printf("%lld\n",query(ansp,ansp,0)); } return 0;}
0 0
- BZOJ 3924 Zjoi2015 幻想乡战略游戏 动态树分治
- bzoj 3924: [Zjoi2015]幻想乡战略游戏 动态树分治
- BZOJ 3924: [Zjoi2015]幻想乡战略游戏 动态树分治
- BZOJ3924: [Zjoi2015]幻想乡战略游戏 动态树分治
- BZOJ3924: [Zjoi2015]幻想乡战略游戏(动态树分治)
- [BZOJ3924][ZJOI2015]幻想乡战略游戏-动态树分治
- bzoj 3924: [Zjoi2015]幻想乡战略游戏
- BZOJ 3924: [Zjoi2015]幻想乡战略游戏
- [点分树] BZOJ 3924 [Zjoi2015]幻想乡战略游戏
- bzoj 3924: [Zjoi2015]幻想乡战略游戏 (树链剖分)
- 3924: [Zjoi2015]幻想乡战略游戏
- [ZJOI2015]幻想乡战略游戏
- [ZJOI2015] 幻想乡战略游戏
- 洛谷3345:幻想乡战略游戏(动态树分治)
- BZOJ3924: [Zjoi2015]幻想乡战略游戏
- 洛谷P3345 [ZJOI2015]幻想乡战略游戏
- bzoj3924幻想乡战略游戏 动态点分治+暴力贪心
- 【ZJOI 2015 幻想乡战略游戏】【动态点分治】
- HTML中清除浮动带来的影响
- 项目零散知识积累(二)
- NS3 Command Line Arguments 使用命令行参数改变脚本
- let和const命令
- 十九、css实现多行文本溢出显示省略号(…)
- bzoj 3924: [Zjoi2015]幻想乡战略游戏 动态树分治
- MyEclipse查看jar包源代码乱码问题解决
- hdu4352——XHXJ's LIS(数位DP+状压)
- Python+Selenium框架设计篇之9-unittest执行脚本方法之makeSuite()
- android动画实现一张图自动旋转、可随时暂停、停止和重置,类似秒表指针旋转动画
- TypeError: Expected int32, got list containing Tensors of type '_Message' instead.
- 2017CCCC决赛 L1-6. 整除光棍
- 初识进程
- 微信支付小记