题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5405

题意: 给你一棵n个节点的树,有点权。

         要求支持两种操作:

    操作1:更改某个节点的权值。

    操作2:给定u,v, 求 Σw[i][j]   i , j 为任意两点且i到j的路径与u到v的路径相交。

解法:

  这是一个大树剖题。 

  容易发现对于一个询问,答案为总点权和的平方 减去 去掉u--v这条链后各个子树的点权和的平方的和。

  开两棵线段树,tag1记录点权和,tag2记录某点的所有轻链子树的点权和的平方的和。

  每次沿着重链往上走时,直接加上这条重链的所有点的tag2和,若有重儿子则直接用tag1计算。由于该条重链必定为其父亲的轻链,故为防止计算重复,还需减去该重链所有点的tag1平方和。

  最后爬到同一颗重链后,还需计算重链上方所有点的贡献。

//HDU 5405//答案为总点权和的平方 减去 去掉u--v这条链后各个子树的点权和的平方的和。
//T1记录点权和,T2记录某点的所有轻链子树的点权和的平方的和
//每次沿着重链往上走时,直接加上这条重链的所有点的tag2和,若有重儿子则直接用tag1计算。
//由于该条重链必定为其父亲的轻链,故为防止计算重复,还需减去该重链所有点的tag1平方和。
//最后爬到同一颗重链后,还需计算重链上方所有点的贡献。#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = 1e5+5;
const int mod = 1e9+7;
struct Tree{LL sum[maxn<<2];void build(){memset(sum,0,sizeof(sum));}void pushup(int rt){sum[rt] = (sum[rt<<1]+sum[rt<<1|1])%mod;}void update(int pos, LL v, int l, int r, int rt){if(l == r){sum[rt] += v;sum[rt] %= mod;return;}int mid = (l+r)>>1;if(pos <= mid) update(pos, v, l, mid, rt<<1);else update(pos, v, mid+1, r, rt<<1|1);pushup(rt);}LL query(int L, int R, int l, int r, int rt){if(L<=l&&r<=R){return sum[rt];}int mid = (l+r)/2;if(R<=mid) return query(L,R,l,mid,rt<<1)%mod;else if(L>mid) return query(L,R,mid+1,r,rt<<1|1)%mod;else return (query(L,mid,l,mid,rt<<1)+query(mid+1,R,mid+1,r,rt<<1|1))%mod;}
}T1, T2;
int head[maxn],n, m,  edgecnt, dfsclk;
struct edge{int to,next;
}E[maxn*2];
int sz[maxn], top[maxn], son[maxn], dep[maxn];
int fa[maxn], tid[maxn], val[maxn];
void init(){edgecnt = 0;dfsclk = 0;memset(head, -1, sizeof(head));memset(son, -1, sizeof(son));
}
void addedge(int u, int v){E[edgecnt].to = v, E[edgecnt].next = head[u], head[u] = edgecnt++;
}
void dfs1(int u, int father, int d){dep[u] = d;fa[u] = father;sz[u] = 1;for(int i = head[u]; ~i; i=E[i].next){int v = E[i].to;if(v == father) continue;dfs1(v, u, d+1);sz[u] += sz[v];if(son[u] == -1 || sz[v]>sz[son[u]]) son[u] = v;}
}
void dfs2(int u, int tp)
{top[u] = tp;tid[u] = ++dfsclk;if(son[u] == -1) return;dfs2(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])dfs2(v,v);}
}
inline LL sqr(int x){return (LL)x*x;
}
void update(int x, int v){int u = top[x];while(fa[u]){LL sum = T1.query(tid[u], tid[u]+sz[u]-1, 1, n, 1);T2.update(tid[fa[u]], ((sqr(val[x]-v)%mod)%mod-(LL)sum*2*(val[x]-v)%mod)%mod, 1, n, 1);u = top[fa[u]];}T1.update(tid[x], v-val[x], 1, n, 1);val[x] = v;
}
LL query(int x, int y){LL ret = 0;while(top[x] != top[y]){if(dep[top[x]]<dep[top[y]]) swap(x,y);ret += T2.query(tid[top[x]], tid[x], 1, n, 1);ret %= mod;if(son[x]!=-1){LL sum = T1.query(tid[son[x]], tid[son[x]]+sz[son[x]]-1, 1, n, 1);ret = ret + sum*sum%mod;ret %= mod;}LL sum = T1.query(tid[top[x]], tid[top[x]]+sz[top[x]]-1, 1, n, 1);ret = (ret - sum*sum%mod + mod)%mod;x = fa[top[x]];}if(dep[x] > dep[y]) swap(x, y);ret += T2.query(tid[x], tid[y], 1, n, 1);ret %= mod;if(son[y]!=-1){LL sum = T1.query(tid[son[y]], tid[son[y]]+sz[son[y]]-1, 1, n, 1);ret = (ret + sum*sum%mod)%mod;}if(fa[x]){LL sum = T1.query(1, n, 1, n, 1) - T1.query(tid[x], tid[x]+sz[x]-1, 1, n, 1);ret = (ret+sum*sum%mod)%mod;}return ret;
}
int main()
{while(~scanf("%d %d", &n,&m)){init();T1.build();T2.build();for(int i=1; i<=n; i++) scanf("%d", &val[i]);for(int i=1; i<n; i++){int u, v;scanf("%d %d", &u,&v);addedge(u, v);addedge(v, u);}dfs1(1, 0, 0);dfs2(1, 1);for(int i=1; i<=n; i++){int x = val[i];val[i] = 0;update(i, x);}while(m--){int op, x, y;scanf("%d %d %d", &op,&x,&y);if(op == 1){update(x, y);}else{LL sum = T1.query(tid[1], tid[1]+sz[1]-1, 1, n, 1);sum = sum*sum;sum = sum-query(x, y);sum = sum%mod;if(sum<0) sum+=mod;printf("%lld\n", sum);}}}return 0;
}

转载于:https://www.cnblogs.com/spfa/p/7327531.html

2015多校第9场 HDU 5405 Sometimes Naive 树链剖分相关推荐

  1. HDU 3966-Aragorn's Story 树链剖分+树状数组

    题目链接 题意:有一棵树,每个节点有权值 有三种操作: I c1 c2 k 从节点c1到节点c2的路径上每个节点权值增加k D c1 c2 k 从节点c1到节点c2的路径上每个节点权值减少k Q i ...

  2. HDU 5274 Dylans loves tree(树链剖分)

    [题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=5274 [题目大意] 给出一棵树,每个点有一个权值,权值可修改,且大于等于0,询问链上出现次数为奇数 ...

  3. HDU - 3966 Aragorn's Story(树链剖分)

    题目传送门:HDU - 3966 Aragorn's Story 题目大意: 存在一个树,树上每个节点为一个阵营,阵营中存在敌人,现在要进行以下操作 I  C1  C2  K :将阵营C1到阵营C2路 ...

  4. hdu 3966(树链剖分+线段树区间更新)

    传送门:Problem 3966 https://www.cnblogs.com/violet-acmer/p/9711441.html 学习资料: [1]线段树区间更新:https://blog.c ...

  5. HDU 2460 Network(双连通+树链剖分+线段树)

    HDU 2460 Network 题目链接 题意:给定一个无向图,问每次增加一条边,问个图中还剩多少桥 思路:先双连通缩点,然后形成一棵树,每次增加一条边,相当于询问这两点路径上有多少条边,这个用树链 ...

  6. HDU 3966 POJ 3237 HYSBZ 2243 HRBUST 2064 树链剖分

    树链剖分是一个很固定的套路 一般用来解决树上两点之间的路径更改与查询 思想是将一棵树分成不想交的几条链 并且由于dfs的顺序性 给每条链上的点或边标的号必定是连着的 那么每两个点之间的路径都可以拆成几 ...

  7. hdu 4897 Little Devil I (树链剖分+线段树)

    题目链接:  http://acm.hdu.edu.cn/showproblem.php?pid=4897 题意: 给你一棵树,一开始每条边都是白色,有三种操作: 1.将 u - v路径上的边转换颜色 ...

  8. hdu 5317 RGCDQ (2015多校第三场第2题)素数打表+前缀和相减求后缀(DP)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5317 题意:F(x) 表示x的不同质因子的个数结果是求L,R区间中最大的gcd( F(i) , F(j ...

  9. hdu 5381 2015多校第八场 莫队算法

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5381 还没学过莫队算法....网上也找不到莫队算法的论文,只能勉强看着别人的代码打下来... 稍微介绍 ...

最新文章

  1. 以下选项不是python文件读操作的是-以下选项不是Python文件读操作的是(____)。...
  2. linux内存和缓冲区,linux – 内存消失了(不,不是缓冲区或缓存)
  3. 洛谷——P1101 单词方阵
  4. CString .Format
  5. requestAnimationFram
  6. 吉利汽车发布澄清公告:并未与百度公司合作生产智能电动车
  7. kinect 手势识别的原理?
  8. python磁盘空间_python3实现磁盘空间监控
  9. 认识 URL 及其编码
  10. jdy视频直播流采集分析
  11. 数据库设计规范(详细)
  12. 计算机回收站设置大小,电脑怎么设置回收站容量 电脑回收站的数据文件位置在哪...
  13. C# Aspose 操作Word书签
  14. 敏捷之路:如何开好迭代评审会
  15. C# 表达式与运算符
  16. python 学习笔记(二)数列
  17. Bootstrap框架: 模拟小风车科技官网
  18. 【Android系统】拨号app
  19. 使用Javascript Rhino重载Java方法
  20. H3C基础配置文档抄录14-虚拟化配置

热门文章

  1. 猫咪视频_猫视频如何进入您的手机
  2. 【博客566】Linux内核系统日志查看方式汇总
  3. 今天的区块链现状是九十年代的互联网?
  4. 视频直播APP源码开发iOS音频播放流程
  5. 五个好用的网络协议分析工具
  6. DB 查询分析器 方便地创建DB2自定义函数
  7. FT232H如何使用jtag接口
  8. IC笔试牛客网verilog刷题总结四
  9. html 如何设置选择图片,html中如何设置默认图片?
  10. RegularJS 0.2.12 发布,JavaScript MVC 框架