hdu 5571 tree (动态点分治)
来源:互联网 发布:二级vb软件序列号 编辑:程序博客网 时间:2024/05/29 10:43
题目描述
传送门
题目大意:给出一棵n个节点的树,每个点有一个权值
题解
带修改的路径问题很适合用动态点分治来做。
这道题如果我们直接考虑
对于每个点统计其作为重心时子树中每一位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[N],point[N],v[N],mi[20],fa[N][20];int belong[N],f[N],size[N],vis[N],deep[N],val[N],sum,root; LL ans,len[N],dis[N];struct data{ LL sum[3][17],cnt[3][17];}tr[N],tr1[N];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); } }}
0 0
- hdu 5571 tree (动态点分治)
- 【HDU】5571 tree【动态点分治】
- HDU 4812 D Tree (树上点分治)
- 【HDU】4812 D Tree 点分治
- HDU 4812 D Tree 点分治
- poj1741 Tree(点分治)
- [POJ1741]Tree(点分治)
- [bzoj1468]Tree(点分治)
- poj1741 tree(点分治)
- 【HDU】5314 Happy King【动态树(点分治)】
- HDU 4812 D Tree (树分治之点分治)
- hdu 4918 Query on the subtree (动态点分治+动态开点+线段树)
- hdu4812 D Tree(点分治)
- POJ 题目1747 Tree(点分治)
- POJ 1741 Tree(点分治)
- POJ 1741 Tree(树+点分治)
- POJ-1471-Tree(点分治)
- poj Tree(树的点分治)
- 如何有效提高asp页面的访问速度
- red5与flex通信 HashMap
- Length of Last Word
- VS2008 引用Oracle.ManagedDataAccess.dll报错的问题
- linux端口解释
- hdu 5571 tree (动态点分治)
- SQL 的备份与还原
- 光栅化
- [树形DP] BZOJ 4824 [Cqoi2017]老C的键盘
- 洛谷 P2825 [HEOI2016]游戏
- TP框架---验证码
- AS3加密解密Des
- ZOJ3950统计
- 明文和密文是什么意思,以及flex与后台交互,Flex根据明文和密钥,采用DES加密算法进行加密,生成密文。