题目大意:
  给你一棵带点权的n个结点的树,有m次询问,每次从树上删掉一条路径(u,v),问删掉每条路径后各个连通块权值和的平方之和。
  每次询问是独立的。

思路:
  首先对树遍历一遍求出每棵子树的权值和。
  然后倍增记录下每个结点往上跳2^k层,深度范围内与这条路径无关的每个连通块的权值和的平方之和。
  然后询问的时候直接倍增往上跳即可,注意跳最后一层的时候要特判一下。

 #include<cstdio>
#include<cctype>
#include<vector>
typedef long long int64;
inline int getint() {
register char ch;
while(!isdigit(ch=getchar()));
register int x=ch^'';
while(isdigit(ch=getchar())) x=(((x<<)+x)<<)+(ch^'');
return x;
}
const int N=;
int w[N],sum[N],par[N],dep[N];
std::vector<int> e[N];
inline void add_edge(const int &u,const int &v) {
e[u].push_back(v);
e[v].push_back(u);
}
void dfs(const int &x,const int &p) {
par[x]=p;
dep[x]=dep[p]+;
sum[x]=w[x];
for(register unsigned i=;i<e[x].size();i++) {
const int &y=e[x][i];
if(y==p) continue;
dfs(y,x);
sum[x]+=sum[y];
}
}
inline int64 sqr(const int64 &x) {
return x*x;
}
inline int lca(int x,int y) {
while(x!=y) {
if(dep[x]<dep[y]) std::swap(x,y);
x=par[x];
}
return x;
}
inline int64 solve(int x,int y) {
int64 ans=;
if(x==y) {
for(register unsigned i=;i<e[x].size();i++) {
const int &y=e[x][i];
if(y==par[x]) continue;
ans+=sqr(sum[y]);
}
ans+=sqr(sum[]-sum[x]);
return ans;
}
if(x!=lca(x,y)) {
for(register unsigned i=;i<e[x].size();i++) {
const int &y=e[x][i];
if(y==par[x]) continue;
ans+=sqr(sum[y]);
}
}
std::swap(x,y);
if(x!=lca(x,y)) {
for(register unsigned i=;i<e[x].size();i++) {
const int &y=e[x][i];
if(y==par[x]) continue;
ans+=sqr(sum[y]);
}
}
while(par[x]!=par[y]&&x!=y) {
if(dep[x]<dep[y]) std::swap(x,y);
for(register unsigned i=;i<e[par[x]].size();i++) {
const int &y=e[par[x]][i];
if(y==par[par[x]]||y==x) continue;
ans+=sqr(sum[y]);
}
x=par[x];
}
if(x!=y) {
for(register unsigned i=;i<e[par[x]].size();i++) {
const int &to=e[par[x]][i];
if(to==par[par[x]]||to==x||to==y) continue;
ans+=sqr(sum[to]);
}
x=par[x];
}
ans+=sqr(sum[]-sum[x]);
return ans;
}
int top;
void dfs1(const int &x,const int &par) {
top=x;
for(register unsigned i=;i<e[x].size();i++) {
const int &y=e[x][i];
if(y==par) continue;
dfs1(y,x);
}
}
int sum2[N];
void dfs2(const int &x,const int &par) {
sum2[x]=sum[par]+w[par];
dep[x]=dep[par]+;
for(register unsigned i=;i<e[x].size();i++) {
const int &y=e[x][i];
if(y==par) continue;
dfs2(y,x);
sum[x]=sum[y]+w[y];
}
}
int main() {
int n=getint(),m=getint();
for(register int i=;i<=n;i++) {
w[i]=getint();
}
for(register int i=;i<n;i++) {
add_edge(getint(),getint());
}
if(n%==) {
dfs1(,);
dfs2(top,);
while(m--) {
int x=getint(),y=getint();
if(dep[x]<dep[y]) std::swap(x,y);
printf("%lld\n",sqr(sum[x])+sqr(sum2[y]));
}
return ;
}
dfs(,);
while(m--) {
printf("%lld\n",solve(getint(),getint()));
}
return ;
}

最新文章

  1. Waves – 赞!超炫交互体验的点击动画效果
  2. SVM与LR的区别以及SVM的优缺点
  3. c++ 模板元编程的一点体会
  4. C#委托Action、Action&lt;T&gt;、Func&lt;T&gt;、Predicate&lt;T&gt;
  5. [Algorithms(Princeton)] Week1 - Percolation
  6. the error code is 2203
  7. stringstream实例
  8. 20130729--Samba的学习
  9. 知乎 zhihu
  10. objective-c中是如何实现线程同步的?
  11. HDOJ 4251 The Famous ICPC Team Again
  12. Swift基础之实现下拉变大和OC下拉变大上拉缩小Demo
  13. Android 模块化/热修复/插件化 框架选用
  14. ESXI6时间源快速同步
  15. 离线安装.NET 3.5
  16. BN(Batch Normalization)
  17. .NET Core开发日志——Runtime IDentifier
  18. Linux TCP server 只能接受一个 TCP 连接
  19. fastdfs+nginx+image_filter安装与生成缩略图
  20. 【极值问题】【CF33C】 Wonderful Randomized Sum

热门文章

  1. inviteflood 洪泛滥工具
  2. 16级第二周寒假作业E题
  3. java程序out of memory【转】
  4. elk系列8之logstash+redis+es的架构来收集apache的日志【转】
  5. Loadrunner下WebTours系统自带的用户名和密码
  6. 你需要知道的Nginx配置二三事
  7. EL(表达式)语言的几种运算符
  8. android 代码设置、打开wifi热点及热点的连接(转)
  9. js复制文字
  10. pip/conda国内镜像--安装包提速