树分治,设当前树的分治中心为x,其子树分治中心为y,则设father[y]=x,分治下去则可以得到一颗重心树,而且树的深度是logn。

  询问操作(x,d),只需要查询重心树上x到重心树根节点上的节点的累加和。假设当前节点是y,那么节点y可以贡献的答案是那些以y为分治中心且到y距离为d-dis(x,y)的节点的总和。当然这样可能会出现重复的情况,重复情况只会出现在包含x的那颗子树上,因此减掉即可。修改操作类似。复杂度O(nlognlogn)

代码

#include<cstdio>
#include<cstring>
#define N 200010
#define LL long long
using namespace std;
int dp,pre[N],p[N],tt[N],vis[N],father[N],s[N],tmp,m;
int n,a,b,i,w[N],L,cnt,tot,len[N],Len[N],start[N],Start[N],v[N];
int deep[N],ss[N][21],fa[N];
int c[N*50];
int min(int a,int b)
{
if (a<b) return a;return b;
}
int lowbit(int x)
{
return x&(-x);
}
void cc(int x,int w,int y)
{
while (x<=L)
{
c[y+x]+=w;
x+=lowbit(x);
}
}
LL sum(int x,int y)
{
LL ans=0;
while (x>0)
{
ans+=c[y+x];
x-=lowbit(x);
}
return ans;
}
void link(int x,int y)
{
dp++;pre[dp]=p[x];p[x]=dp;tt[dp]=y;
}
void gao(int x)
{
int i;
i=p[x];
while (i)
{
if (tt[i]!=fa[x])
{
fa[tt[i]]=x;
deep[tt[i]]=deep[x]+1;
gao(tt[i]);
}
i=pre[i];
}
}
int lca(int x,int y)
{
if(deep[x]>deep[y])x^=y^=x^=y;
int i;
for(i=19;i>=0;i--)
{
if(deep[y]-deep[x]>=(1<<i))
{
y=ss[y][i];
}
}
if(x==y)return x;
for(i=19;i>=0;i--)
{
if(ss[x][i]!=ss[y][i])
{
x=ss[x][i];
y=ss[y][i];
}
}
return fa[x];
}
void getroot(int x,int fa,int sum)
{
int i,flag=0;
i=p[x];s[x]=1;
while (i)
{
if ((!vis[tt[i]])&&(tt[i]!=fa))
{
getroot(tt[i],x,sum);
s[x]+=s[tt[i]];
if (s[tt[i]]>sum/2) flag=1;
}
i=pre[i];
}
if (sum-s[x]>sum/2) flag=1;
if (!flag) tmp=x;
}
void dfs(int x,int fa,int dis)
{
int i;
i=p[x];
if (dis>cnt) cnt=dis;
v[dis]+=w[x];
while (i)
{
if ((!vis[tt[i]])&&(tt[i]!=fa))
dfs(tt[i],x,dis+1);
i=pre[i];
}
}
void clear()
{
int i;
for (i=1;i<=cnt;i++)
v[i]=0;cnt=0;
}
int work(int x,int fa,int sum)
{
int i,root,t;
getroot(x,0,sum);
root=tmp;
father[root]=fa;
i=p[root];
vis[root]=1;
while (i)
{
if (!vis[tt[i]])
{
if (s[root]>s[tt[i]])
t=work(tt[i],root,s[tt[i]]);
else
t=work(tt[i],root,sum-s[root]);
//------dist(root,point in subtree t)-------- dfs(tt[i],0,2);
Len[t]=cnt;
Start[t]=tot;
for (int j=1;j<=cnt;j++)
{
L=cnt;
cc(j,v[j],Start[t]);
}
tot+=cnt;
clear(); }
i=pre[i];
}
vis[root]=0; //--------dist(root,all point)---------- dfs(root,0,1);
len[root]=cnt;
start[root]=tot;
for (i=1;i<=cnt;i++)
{
L=cnt;
cc(i,v[i],start[root]);
}
tot+=cnt;
clear(); return root;
}
LL query(int x,int d)
{
int y=0,z=x,t;
LL ans=0;
while (x)
{
t=lca(x,z);
t=deep[x]+deep[z]-2*deep[t];
L=len[x];
ans+=sum(min(L,d-t+1),start[x]); if (y)
{
L=Len[y];
ans-=sum(min(L,d-t+1),Start[y]);
}
y=x;
x=father[x];
}
return ans;
}
void change(int x,int w)
{
int y=0,z=x,t;
while (x)
{
t=lca(x,z);
t=deep[x]+deep[z]-2*deep[t];
L=len[x];
cc(t+1,w,start[x]); if (y)
{
L=Len[y];
cc(t+1,w,Start[y]);
}
y=x;
x=father[x];
}
}
int main()
{
while (scanf("%d%d",&n,&m)!=EOF)
{
dp=0;memset(p,0,sizeof(p));
for (i=1;i<=tot;i++)
c[i]=0;tot=0; for (i=1;i<=n;i++)
scanf("%d",&w[i]);
for (i=1;i<n;i++)
{
scanf("%d%d",&a,&b);
link(a,b);
link(b,a);
}
gao(1);
for(i=1;i<=n;i++)
ss[i][0]=fa[i];
for(int h=1;h<20;h++)
{
for(i=1;i<=n;i++)
{
ss[i][h]=ss[ss[i][h-1]][h-1];
}
}
work(1,0,n); for (i=1;i<=m;i++)
{
getchar();
char ch;
scanf("%c%d%d",&ch,&a,&b);
if (ch=='?')
printf("%I64d\n",query(a,b));
else
{
change(a,b-w[a]);
w[a]=b;
}
} }
}

  

hdu4918 Query on the subtree的更多相关文章

  1. HDU4918 Query on the subtree 点分治+树状数组

    bobo has a tree, whose vertices are conveniently labeled by 1,2,…,n. At the very begining, the i-th ...

  2. HDU 4918 Query on the subtree(动态点分治+树状数组)

    题意 给定一棵 \(n\) 个节点的树,每个节点有点权.完成 \(q\) 个操作--操作分两种:修改点 \(x\) 的点权.查询与 \(x\) 距离小于等于 \(d\) 的权值总和. \(1 \leq ...

  3. ZOJ 3686 A Simple Tree Problem

    A Simple Tree Problem Time Limit: 3 Seconds      Memory Limit: 65536 KB Given a rooted tree, each no ...

  4. Sphinx 2.2.11-release reference manual

    1. Introduction 1.1. About 1.2. Sphinx features 1.3. Where to get Sphinx 1.4. License 1.5. Credits 1 ...

  5. zoj3686(线段树的区间更新)

    对线段树的区间更新有了初步的了解... A Simple Tree Problem Time Limit: 3 Seconds      Memory Limit: 65536 KB Given a ...

  6. ZOJ 3686 A Simple Tree Problem(线段树)

    Description Given a rooted tree, each node has a boolean (0 or 1) labeled on it. Initially, all the ...

  7. Random Numbers Gym - 101466K dfs序+线段树

    Tamref love random numbers, but he hates recurrent relations, Tamref thinks that mainstream random g ...

  8. BNU 28887——A Simple Tree Problem——————【将多子树转化成线段树+区间更新】

    A Simple Tree Problem Time Limit: 3000ms Memory Limit: 65536KB This problem will be judged on ZJU. O ...

  9. xtu数据结构 I. A Simple Tree Problem

    I. A Simple Tree Problem Time Limit: 3000ms Memory Limit: 65536KB 64-bit integer IO format: %lld     ...

随机推荐

  1. HW 研发体系机构的几个术语

    PDT(product development team)产品开发团队   类似于产品经理 程序员 --  PL -- PM  --开发代表 -- PDT LEADER --------------- ...

  2. 【Android开发学习笔记】【随笔】UI线程

    概念 UI线程 是Android中的主线程,涉及到UI方面的一些操作都需要在ui线程中进行操作 在非ui线程中想操作ui,就会报错 android.view.ViewRoot$CalledFromWr ...

  3. oracle常用的SQL语句

    一些常用的SQL语句: --建表 create table adolph (id number(10,0),              name varchar2(20),              ...

  4. 学习之js绑定事件

    由于ie中绑定事件的bug,所以产生了用原生的实践操作来模拟事件绑定的方法,跟着李炎恢学的一招. function addEvent(obj, type, fn){ if(obj.addEventLi ...

  5. MongoDB聚合查询

    1.count:查询记录条数 db.user.count() 它也跟find一样可以有条件的 db.user.count({}) 2.distinct:用来找出给定键的所有不同的值 db.user.d ...

  6. centos 安装 openerp

    遇到问题:近日公司提出openerp的搭建,觉得openerp里的有些模块比较适合公司,openerp的运作,估计会有利于公司系统化的管理.于是我就去了解openrp,然后来搭建这套强大的系统. 解决 ...

  7. 错误提示: An App ID with identifier "*****" is not avaliable. Please enter a different string.

    百度了很多,但大多的解决办法就是 更改BundleID,的确管用,,但是有的情况下,你需要跟同事合作,公用同一个BundleID, 我是这样处理的:工具栏中打开Window—project删除所有工程 ...

  8. H5 -- 本地存储计数器的值 和前端校验用户

    1. 存储计数器的值 <!DOCTYPE html> <html> <head lang="en"> <meta charset=&quo ...

  9. Fedora8上Apache Httpd与Tomcat6初集成

    系统信息: 环境: Linux version :2.6.23.1-42.fc8,gcc version 4.1.2 20070925 Apache Httpd version: 2.2.6.3-3 ...

  10. asp.net中session的原理及应用

    Session简介丶特性 1.Session是一种Web会话中的常用状态之一. 2.Session提供了一种把信息保存在服务器内存中的方式.他能储存任何数据类型,包含自定义对象. 3.每个客户端的Se ...