首页
Web开发
Windows程序
编程语言
数据库
移动开发
系统相关
微信
其他好文
会员
首页
>
其他好文
> 详细
树链剖分 FZU 2082
时间:
2015-03-09 12:56:51
阅读:
166
评论:
0
收藏:
0
[点我收藏+]
标签:
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn = 50005;
int val[maxn];
struct node
{
int l,r;
long long sum;
} xds[maxn<<2];
void build(int ID,int l,int r)
{
xds[ID].l=l;
xds[ID].r=r;
if(r==l)
{
xds[ID].sum=val[l];
return ;
}
int mid=(l+r)>>1;
build(ID<<1,l,mid);
build(ID<<1|1,mid+1,r);
xds[ID].sum=xds[ID<<1].sum+xds[ID<<1|1].sum;
}
long long query(int ID,int l,int r)
{
if(xds[ID].l==l&&xds[ID].r==r)
return xds[ID].sum;
int mid=(xds[ID].l+xds[ID].r)>>1;
if(r<=mid)
return query(ID<<1,l,r);
else if(l>mid)
return query(ID<<1|1,l,r);
else
return query(ID<<1,l,mid)+query(ID<<1|1,mid+1,r);
}
void gengxin(int ID,int l,int v)
{
if(xds[ID].l==l&&xds[ID].r==l)
{
xds[ID].sum=v;
return ;
}
int mid=(xds[ID].l+xds[ID].r)>>1;
if(l<=mid)
gengxin(ID<<1,l,v);
else
gengxin(ID<<1|1,l,v);
xds[ID].sum=xds[ID<<1].sum+xds[ID<<1|1].sum;
}
int id,ne,N,M;
int first[maxn],next[maxn<<1],top[maxn],idx[maxn],far[maxn],son[maxn],dep[maxn],cnt[maxn];
/*
first和next是邻接表数组,top存的是链的顶端节点,idx存的剖分后每个边在线段树中的位置,far【u】记录的是u节点的父亲节点
son[u]的重儿子节点,dep[u]记录的是u节点在树中的深度,cnt[u]记录的是u节点的所有节点(是所有节点哦)的个数包括自身节点的个数
*/
struct Edge//邻接表的存储结构体
{
int u,v,w;
void set(int u,int v,int w)
{
this->u=u;
this->v=v;
this->w=w;
}
} ed[maxn<<1];
void add_Edge(int u,int v,int w)//邻接表加边
{
ed[ne].set(u,v,w);
next[ne]=first[u];
first[u]=ne++;
}
void dfs(int u,int pre,int d)//递归求出,far,son,dep,cnt,u表示当前节点,pre表示u的父亲节点,d表示深度
{
far[u]=pre;
son[u]=0;
dep[u]=d;
cnt[u]=1;
for(int i=first[u]; i+1; i=next[i])//遍历以u为根节点的子节点
{
int v=ed[i].v;
if(v==far[u])//因为是无向图所以要把u的父亲节点排除外
continue;
dfs(v,u,d+1);
cnt[u]+=cnt[v];
if(cnt[son[u]]<cnt[v])//判断重儿子,也就是节点数最多的儿子
son[u]=v;
}
}
void dfs(int u,int root)//u代表当前节点,root代表根节点
{
idx[u]=++id;//让在同一重链上的点在线段树种相邻
top[u]=root;
if(son[u]) dfs(son[u],root);//如果u有重儿子就,先递归重儿子,因为重儿子和根节点的顶端节点相同,还有要让同一重链上的节点相邻
for(int i=first[u]; i+1; i=next[i])
{
int v=ed[i].v;
if(v==far[u]||v==son[u])//当v不是u父亲节点也不是u的重儿子时就是u的轻儿子
continue;
dfs(v,v);//轻儿子的顶端节点就是自身
}
}
void init()
{
int u,v,w;
id=ne=0;
memset(first,-1,sizeof(first));
for(int i=1; i<N; i++)
{
scanf("%d%d%d",&u,&v,&w);
add_Edge(u,v,w);
add_Edge(v,u,w);
}
dfs(1,0,0);
dfs(1,1);
for(int i=0; i<N-1; i++)//调整点来达到把边的花费存到深度较大的节点所在的线段树中的位置,比如说a-b-c相连用b存放a-b的花费,c存放b-c的花费
{
int t=i<<1;
if(dep[ed[t].u]<dep[ed[t].v])
swap(ed[t].u,ed[t].v);
val[idx[ed[t].u]]=ed[t].w;
}
build(1,1,id);//建树
}
long long slove(int u,int v)
{//轻链的是一条边一条边的计算,重链是是一条链的计算
int p=top[u],q=top[v];
long long ret=0;
while(p!=q)//p==q说明已经链的顶点已经是同一点
{
if(dep[p]<dep[q])//一直判断深浅的话就能很好的计算重链了,假如说一直从一点向另一点算的话就会就不能实现重链上一次性算完了,就如新浪博客上图的10-11的花费如果一直从10相11算的话树链剖分和不剖分就没有意义了
{
swap(p,q);
swap(u,v);
}
ret+=query(1,idx[p],idx[u]);
u=far[p];
p=top[u];
}
if(u==v))//说明是轻链
return ret;
if(dep[u]>dep[v])//说明是重链且不是根节点,在重链上求一段的花费
swap(u,v);
ret+=query(1,idx[son[u]],idx[v]);
return ret;
}
int main()
{
while(scanf("%d%d",&N,&M)!=EOF)
{
init();
for(int i=0; i<M; i++)
{
int k,u,v;
scanf("%d%d%d",&k,&u,&v);
if(k)
printf("%lld\n",slove(u,v));
else
gengxin(1,idx[ed[u*2-2].u],v);
}
}
return 0;
}
树链剖分 FZU 2082
标签:
原文地址:http://blog.csdn.net/u013491149/article/details/44152325
踩
(
0
)
赞
(
0
)
举报
评论
一句话评论(
0
)
登录后才能评论!
分享档案
更多>
2021年07月29日 (22)
2021年07月28日 (40)
2021年07月27日 (32)
2021年07月26日 (79)
2021年07月23日 (29)
2021年07月22日 (30)
2021年07月21日 (42)
2021年07月20日 (16)
2021年07月19日 (90)
2021年07月16日 (35)
周排行
更多
分布式事务
2021-07-29
OpenStack云平台命令行登录账户
2021-07-29
getLastRowNum()与getLastCellNum()/getPhysicalNumberOfRows()与getPhysicalNumberOfCells()
2021-07-29
【K8s概念】CSI 卷克隆
2021-07-29
vue3.0使用ant-design-vue进行按需加载原来这么简单
2021-07-29
stack栈
2021-07-29
抽奖动画 - 大转盘抽奖
2021-07-29
PPT写作技巧
2021-07-29
003-核心技术-IO模型-NIO-基于NIO群聊示例
2021-07-29
Bootstrap组件2
2021-07-29
友情链接
兰亭集智
国之画
百度统计
站长统计
阿里云
chrome插件
新版天听网
关于我们
-
联系我们
-
留言反馈
© 2014
mamicode.com
版权所有 联系我们:gaon5@hotmail.com
迷上了代码!