hdu 5571 tree (动态点分治)
2017-04-21 08:11
239 查看
题目描述
传送门
题目大意:给出一棵n个节点的树,每个点有一个权值ai,一个点对(i,j)i<j的贡献为(ai xor aj)∗dis(i,j),求每次修改一个节点后树中所有点对的贡献和。题解
带修改的路径问题很适合用动态点分治来做。这道题如果我们直接考虑ai xor aj,不好做。所以我们考虑把每一位分离开,那么问题就转化成统计01对的个数以及路径和的问题。
对于每个点统计其作为重心时子树中每一位01的个数即路径和即可。
代码
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #define M 15 #define N 60003 #define inf 1000000000 #define LL long long using namespace std; int tot,n,m,nxt ,point ,v ,mi[20],fa [20]; int belong ,f ,size ,vis ,deep ,val ,sum,root; LL ans,len ,dis ; struct data{ LL sum[3][17],cnt[3][17]; }tr ,tr1 ; void add(int x,int y,int z) { tot++; nxt[tot]=point[x]; point[x]=tot; v[tot]=y; len[tot]=z; tot++; nxt[tot]=point[y]; point[y]=tot; v[tot]=x; len[tot]=z; } void dfs(int x,int father) { deep[x]=deep[father]+1; for (int i=1;i<=17;i++) { if (deep[x]-mi[i]<0) break; fa[x][i]=fa[fa[x][i-1]][i-1]; } for (int i=point[x];i;i=nxt[i]) { if (v[i]==father) continue; fa[v[i]][0]=x; dis[v[i]]=dis[x]+len[i]; dfs(v[i],x); } } int lca(int x,int y) { if (deep[x]<deep[y]) swap(x,y); int k=deep[x]-deep[y]; for (int i=0;i<=17;i++) if ((k>>i)&1) x=fa[x][i]; if (x==y) return x; for (int i=17;i>=0;i--) if (fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i]; return fa[x][0]; } void getroot(int x,int father) { f[x]=0; size[x]=1; for (int i=point[x];i;i=nxt[i]){ if (v[i]==father||vis[v[i]]) continue; getroot(v[i],x); size[x]+=size[v[i]]; f[x]=max(f[x],size[v[i]]); } f[x]=max(f[x],sum-size[x]); if (f[x]<f[root]) root=x; } LL dist(int x,int y) { return dis[x]+dis[y]-2*dis[lca(x,y)]; } void divi(int x,int father) { belong[x]=father; vis[x]=1; for (int i=point[x];i;i=nxt[i]){ if (vis[v[i]]) continue; root=0; sum=size[v[i]]; getroot(v[i],x); divi(root,x); } } void change(int u,int son,int v,int v1,LL tap) { int t=v1; LL D=dist(u,v); if(u==v) { for (int i=0;i<=M;i++) { int opt=(t>>i)&1; opt^=1; LL sum=tr[u].sum[opt][i]; LL cnt=tr[u].sum[opt][i]; if (cnt) ans+=tap*(sum+cnt*D)*(LL)mi[i]; } } else { for (int i=0;i<=M;i++) { int opt=(t>>i)&1; opt^=1; LL sum=tr[u].sum[opt][i]-tr1[son].sum[opt][i]; LL cnt=tr[u].cnt[opt][i]-tr1[son].cnt[opt][i]; if (cnt) ans+=tap*(sum+cnt*D)*(LL)mi[i]; } } for (int i=0;i<=M;i++) { tr[u].sum[(t>>i)&1][i]+=D*tap; tr[u].cnt[(t>>i)&1][i]+=tap; } if (!belong[u]) return; int f=belong[u]; D=dist(f,v); t=v1; for (int i=0;i<=M;i++) { tr1[u].sum[(t>>i)&1][i]+=D*tap; tr1[u].cnt[(t>>i)&1][i]+=tap; } change(belong[u],u,v,v1,tap); } int main() { freopen("a.in","r",stdin); freopen("my.out","w",stdout); mi[0]=1; for (int i=1;i<=17;i++) mi[i]=mi[i-1]*2; while (scanf("%d",&n)!=EOF) { tot=0; ans=0; memset(point,0,sizeof(point)); memset(dis,0,sizeof(dis)); memset(vis,0,sizeof(vis)); memset(fa,0,sizeof(fa)); for (int i=1;i<=n;i++) for (int j=0;j<=M;j++) for (int k=0;k<=1;k++) tr[i].sum[k][j]=tr[i].cnt[k][j]=tr1[i].sum[k][j]=tr1[i].cnt[k][j]=0; for (int i=1;i<=n;i++) scanf("%d",&val[i]); for (int i=1;i<n;i++) { int x,y,z; scanf("%d%d%d",&x,&y,&z); add(x,y,z); } dfs(1,0); sum=n; root=0; f[0]=inf; getroot(1,0); divi(root,0); for (int i=1;i<=n;i++) change(i,i,i,val[i],1); scanf("%d",&m); for (int i=1;i<=m;i++) { int x,v1; scanf("%d%d",&x,&v1); change(x,x,x,val[x],-1); change(x,x,x,v1,1); val[x]=v1; printf("%lld\n",ans); } } }
相关文章推荐
- 【HDU】5571 tree【动态点分治】
- HDU 4718 The LCIS on the Tree (动态树LCT)
- 【HDU】4812 D Tree 点分治
- HDU D Tree [点分治]
- Hdu 5401 Persistent Link/cut Tree 树上分治/记忆化搜索
- HDU 6065 RXD, tree and sequence(在线倍增LCA+CDQ分治+离线tarjan-LCA+dp)
- HDU 3924 Extend-Tree 【一道不错的分治题目】
- HDU - 5002 Tree (动态树模板)
- SPOJ QTREE4 Query on a tree IV ——动态点分治
- [LCT 动态最大生成树] HDU 5398 GCD Tree
- hdu 6183 Color it(动态线段树,cdq分治)
- hdu 4670 Cube number on a tree(点分治)
- hdu 5398 GCD Tree 2015多校联合训练赛#9 LCT,动态生成树
- 【HDU】5314 Happy King【动态树(点分治)】
- SPOJ QTREE Query on a tree V ——动态点分治
- hdu 4670 Cube number on a tree(点分治)
- HDU 5002 Tree(动态树LCT)(2014 ACM/ICPC Asia Regional Anshan Online)
- 【HDU】5267 pog loves szh IV【动态点分治】
- 【树的分治】 HDU 4670 Cube number on a tree
- hdu 4918 Query on the subtree (动态点分治+动态开点+线段树)