【块状树】【树链剖分】bzoj1036 [ZJOI2008]树的统计Count
很早之前用树链剖分写过,但是代码太长太难写,省选现场就写错了。
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
#define lson rt<<1,l,m
#define rson rt<<1|1,m+1,r
#define maxn 60000
int n,m,u,v;
int V[maxn],Next[maxn],First[maxn];
int Val[maxn];
int fa[maxn],dep[maxn],son[maxn],siz[maxn],top[maxn],Num[maxn],tot,en;
int maxv[maxn<<],sumv[maxn<<];
bool vis[maxn];
char s[];
inline void AddEdge(int UU,int VV)
{
V[++en]=VV;
Next[en]=First[UU];
First[UU]=en;
}
int query_sum(int ql,int qr,int rt,int l,int r)
{
if(ql<=l&&r<=qr)
return sumv[rt];
int m=l+r>>,ans=;
if(ql<=m)
ans+=query_sum(ql,qr,lson);
if(m<qr)
ans+=query_sum(ql,qr,rson);
return ans;
}
int query_max(int ql,int qr,int rt,int l,int r)
{
if(ql<=l&&r<=qr)
return maxv[rt];
int m=l+r>>,ans=-;
if(ql<=m)
ans=max(ans,query_max(ql,qr,lson));
if(m<qr)
ans=max(ans,query_max(ql,qr,rson));
return ans;
}
void update(int p,int v,int rt,int l,int r)
{
int m=l+r>>;
if(l==r)
{
maxv[rt]=sumv[rt]=v;
return;
}
if(p<=m)
update(p,v,lson);
else
update(p,v,rson);
sumv[rt]=sumv[rt<<]+sumv[(rt<<)+];
maxv[rt]=max(maxv[rt<<],maxv[(rt<<)+]);
}
inline void Change(int p,int v)
{
update(p,v,,,n);
}
inline int Query_sum(int u,int v)
{
int f1=top[u],f2=top[v],res=;
while(f1!=f2)
{
if(dep[f1]<dep[f2])
{
swap(u,v);
swap(f1,f2);
}
res+=query_sum(Num[f1],Num[u],,,n);
u=fa[f1];
f1=top[u];
}
if(dep[u]>dep[v])
swap(u,v);
return res+query_sum(Num[u],Num[v],,,n);
}
inline int Query_max(int u,int v)
{
int f1=top[u],f2=top[v],res=-;
while(f1!=f2)
{
if(dep[f1]<dep[f2])
{
swap(u,v);
swap(f1,f2);
}
res=max(res,query_max(Num[f1],Num[u],,,n));
u=fa[f1];
f1=top[u];
}
if(dep[u]>dep[v])
swap(u,v);
return max(res,query_max(Num[u],Num[v],,,n));
}
void dfs1(int cur,int father,int depth)
{
fa[cur]=father;
dep[cur]=depth;
siz[cur]=;
for(int i=First[cur];i;i=Next[i])
if(!vis[V[i]])
{
vis[V[i]]=true;
dfs1(V[i],cur,depth+);
siz[cur]+=siz[V[i]];
if(siz[V[i]]>siz[son[cur]])
son[cur]=V[i];
vis[V[i]]=false;
}
}
void dfs2(int cur)
{
if(son[cur]&&!vis[son[cur]])
{
vis[son[cur]]=true;
top[son[cur]]=top[cur];
Num[son[cur]]=++tot;
Change(tot,Val[son[cur]]);
dfs2(son[cur]);
vis[son[cur]]=false;
}
for(int i=First[cur];i;i=Next[i])
if(son[cur]!=V[i]&&!vis[V[i]])
{
vis[V[i]]=true;
top[V[i]]=V[i];
Num[V[i]]=++tot;
Change(tot,Val[V[i]]);
dfs2(V[i]);
vis[V[i]]=false;
}
}
int main()
{
scanf("%d",&n);
for(int i=;i<n;i++)
{
scanf("%d%d",&u,&v);
AddEdge(u,v);
AddEdge(v,u);
}
for(int i=;i<=n;i++)
scanf("%d",&Val[i]);
top[]=;
Num[]=++tot;
Change(tot,Val[]);
vis[]=true;
dfs1(,,);
dfs2();
scanf("%d",&m);
for(int i=;i<=m;i++)
{
scanf("%s",s);
if(s[]=='H')
{
scanf("%d%d",&u,&v);
Change(Num[u],v);
}
else if(s[]=='M')
{
scanf("%d%d",&u,&v);
printf("%d\n",Query_max(u,v));
}
else
{
scanf("%d%d",&u,&v);
printf("%d\n",Query_sum(u,v));
}
}
return ;
}
学了个块状树,好写不少,而且常数较小,比链剖慢不了多少。
在dfs时分块,只要当前块满了sqrt(n),就分新的一块。
对每个点,维护从这个点到该块的根(top)的路径上的答案。
更新的时候,只会对 该点 在该块内的子树 造成影响。
询问时,暴力LCA。
这样更新和询问都是O(sqrt(n))的。
Orz zky。
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
struct Graph
{
int v[],first[],next[],en;
void AddEdge(const int &a,const int &b)
{v[++en]=b;next[en]=first[a];first[a]=en;}
};
Graph G[];
int fa[],dep[],top[],siz[],sz;
int maxv[],sumv[],w[];
int n,x,y,q;
char op[];
void makeblock(int cur)
{
for(int i=G[].first[cur];i;i=G[].next[i])
if(G[].v[i]!=fa[cur])
{
dep[G[].v[i]]=dep[cur]+;
fa[G[].v[i]]=cur;
if(siz[top[cur]]<sz)
{
siz[top[cur]]++;
top[G[].v[i]]=top[cur];
G[].AddEdge(cur,G[].v[i]);
}
makeblock(G[].v[i]);
}
}
void dfs(int cur,int Sumnow,int Maxnow)
{
maxv[cur]=Maxnow;
sumv[cur]=Sumnow;
for(int i=G[].first[cur];i;i=G[].next[i])
dfs(G[].v[i],Sumnow+w[G[].v[i]],max(Maxnow,w[G[].v[i]]));
}
inline void update(int p,int val)
{
w[p]=val;
if(p==top[p]) dfs(p,val,val);
else dfs(p,val+sumv[fa[p]],max(val,maxv[fa[p]]));
}
inline int Query_max(int u,int v)
{
int res=-;
while(u!=v)
{
if(top[u]==top[v])
{
if(dep[u]<dep[v]) swap(u,v);
res=max(res,w[u]);
u=fa[u];
}
else
{
if(dep[top[u]]<dep[top[v]]) swap(u,v);
res=max(res,maxv[u]);
u=fa[top[u]];
}
}
return max(res,w[u]);
}
inline int Query_sum(int u,int v)
{
int res=;
while(u!=v)
{
if(top[u]==top[v])
{
if(dep[u]<dep[v])
swap(u,v);
res+=w[u];
u=fa[u];
}
else
{
if(dep[top[u]]<dep[top[v]])
swap(u,v);
res+=sumv[u];
u=fa[top[u]];
}
}
return res+w[u];
}
int main()
{
scanf("%d",&n);
for(int i=;i<n;i++)
{
scanf("%d%d",&x,&y);
G[].AddEdge(x,y);
G[].AddEdge(y,x);
}
sz=sqrt(n);
for(int i=;i<=n;i++)
{
scanf("%d",&w[i]);
top[i]=i;
siz[i]=;
}
makeblock();
for(int i=;i<=n;i++)
if(top[i]==i) dfs(i,w[i],w[i]);
scanf("%d",&q);
for(int i=;i<=q;i++)
{
scanf("%s%d%d",op,&x,&y);
if(op[]=='M') printf("%d\n",Query_max(x,y));
else if(op[]=='H') update(x,y);
else printf("%d\n",Query_sum(x,y));
}
return ;
}
【块状树】【树链剖分】bzoj1036 [ZJOI2008]树的统计Count的更多相关文章
- [BZOJ1036][ZJOI2008]树的统计Count 解题报告|树链剖分
树链剖分 简单来说就是数据结构在树上的应用.常用的为线段树splay等.(可现在splay还不会敲囧) 重链剖分: 将树上的边分成轻链和重链. 重边为每个节点到它子树最大的儿子的边,其余为轻边. 设( ...
- bzoj 1036 [ZJOI2008]树的统计Count(树链剖分,线段树)
1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 10677 Solved: 4313[Submit ...
- bzoj 4034 [HAOI2015] T2(树链剖分,线段树)
4034: [HAOI2015]T2 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 1536 Solved: 508[Submit][Status] ...
- poj 3237 Tree(树链剖分,线段树)
Tree Time Limit: 5000MS Memory Limit: 131072K Total Submissions: 7268 Accepted: 1969 Description ...
- bzoj 3626 [LNOI2014]LCA(离线处理+树链剖分,线段树)
3626: [LNOI2014]LCA Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1272 Solved: 451[Submit][Status ...
- bzoj 2243 [SDOI2011]染色(树链剖分,线段树)
2243: [SDOI2011]染色 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 4637 Solved: 1726[Submit][Status ...
- HDU 4366 Successor(树链剖分+zkw线段树+扫描线)
[题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=4366 [题目大意] 有一个公司,每个员工都有一个上司,所有的人呈树状关系,现在给出每个人的忠诚值和 ...
- 【BZOJ3531】旅行(树链剖分,线段树)
[BZOJ3531]旅行(树链剖分,线段树) 题面 Description S国有N个城市,编号从1到N.城市间用N-1条双向道路连接,满足 从一个城市出发可以到达其它所有城市.每个城市信仰不同的宗教 ...
- 【BZOJ5507】[GXOI/GZOI2019]旧词(树链剖分,线段树)
[BZOJ5507][GXOI/GZOI2019]旧词(树链剖分,线段树) 题面 BZOJ 洛谷 题解 如果\(k=1\)就是链并裸题了... 其实\(k>1\)发现还是可以用类似链并的思想,这 ...
- [bzoj4196][Noi2015]软件包管理器_树链剖分_线段树
软件包管理器 bzoj-4196 Noi-2015 题目大意:Linux用户和OSX用户一定对软件包管理器不会陌生.通过软件包管理器,你可以通过一行命令安装某一个软件包,然后软件包管理器会帮助你从软件 ...
随机推荐
- HDU 2126 01背包(求方案数)
Buy the souvenirs Time Limit: 10000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Other ...
- weblogic的安装和注意的问题以及在idea怎么用weblogic启动一个web服务
第一步下载weblogic: 大家可以通过我的网盘下载weblogic,地址如下 https://pan.baidu.com/s/1NkZ_Gd-xfim5YGcdtjYoUw 第二步安装weblog ...
- bzoj 1201[HNOI2005]数三角形 1202 [HNOI2005]狡猾的商人 暴力 权值并查集
[HNOI2005]数三角形 Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 349 Solved: 234[Submit][Status][Disc ...
- ERROR: Found lingering reference file hdfs
Found lingering reference异常 ERROR: Found lingering reference file hdfs://jiujiang1:9000/hbase/month_ ...
- lvm扩容
111 mkfs -t xfs /dev/sda3 112 pvcreate /dev/sda3 113 vgs 114 vgextend cl /dev/sda3 115 lvscan 116 vg ...
- 在Ubuntu下编译WebKit源码--qt
转载自:http://www.cnblogs.com/panderen/archive/2011/10/18/2216154.html 在朋友的介绍下有幸認识了WebKit这个让人心动的开源浏览器内核 ...
- 【BZOJ2338】【HNOI2011】数矩形 [计算几何]
数矩形 Time Limit: 20 Sec Memory Limit: 128 MB[Submit][Status][Discuss] Description 最近某歌手在研究自己的全国巡回演出, ...
- bzoj1833: [ZJOI2010]count 数字计数 && codevs1359 数字计数
bzoj1833 codevs1359 这道题也是道数位dp 因为0有前导0这一说卡了很久 最后发现用所有位数减1~9的位数就okay.....orzczl大爷 其他就跟51nod那道统计1出现次数一 ...
- 下拉列表 JComboBox 的使用
下拉列表(JComboBox)通常显示一个可选条目,允许用户在一个下拉列表中选择不同条目,用户也可以在文本区内输入选择项. package first; import java.awt.FlowLay ...
- bzoj 1293 贪心
首先我们可以将这道题看成一个数轴,数轴其中的某些点存在一些颜色,我们要选取最短的一段,使这段存 在所有颜色,那么我们使用指针i,j表示在j-i位置中包含的颜色,那么初值是0,0,我们先i++,同时添加 ...