很早之前用树链剖分写过,但是代码太长太难写,省选现场就写错了。

 #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的更多相关文章

  1. [BZOJ1036][ZJOI2008]树的统计Count 解题报告|树链剖分

    树链剖分 简单来说就是数据结构在树上的应用.常用的为线段树splay等.(可现在splay还不会敲囧) 重链剖分: 将树上的边分成轻链和重链. 重边为每个节点到它子树最大的儿子的边,其余为轻边. 设( ...

  2. bzoj 1036 [ZJOI2008]树的统计Count(树链剖分,线段树)

    1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 10677  Solved: 4313[Submit ...

  3. bzoj 4034 [HAOI2015] T2(树链剖分,线段树)

    4034: [HAOI2015]T2 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 1536  Solved: 508[Submit][Status] ...

  4. poj 3237 Tree(树链剖分,线段树)

    Tree Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 7268   Accepted: 1969 Description ...

  5. bzoj 3626 [LNOI2014]LCA(离线处理+树链剖分,线段树)

    3626: [LNOI2014]LCA Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1272  Solved: 451[Submit][Status ...

  6. bzoj 2243 [SDOI2011]染色(树链剖分,线段树)

    2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 4637  Solved: 1726[Submit][Status ...

  7. HDU 4366 Successor(树链剖分+zkw线段树+扫描线)

    [题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=4366 [题目大意] 有一个公司,每个员工都有一个上司,所有的人呈树状关系,现在给出每个人的忠诚值和 ...

  8. 【BZOJ3531】旅行(树链剖分,线段树)

    [BZOJ3531]旅行(树链剖分,线段树) 题面 Description S国有N个城市,编号从1到N.城市间用N-1条双向道路连接,满足 从一个城市出发可以到达其它所有城市.每个城市信仰不同的宗教 ...

  9. 【BZOJ5507】[GXOI/GZOI2019]旧词(树链剖分,线段树)

    [BZOJ5507][GXOI/GZOI2019]旧词(树链剖分,线段树) 题面 BZOJ 洛谷 题解 如果\(k=1\)就是链并裸题了... 其实\(k>1\)发现还是可以用类似链并的思想,这 ...

  10. [bzoj4196][Noi2015]软件包管理器_树链剖分_线段树

    软件包管理器 bzoj-4196 Noi-2015 题目大意:Linux用户和OSX用户一定对软件包管理器不会陌生.通过软件包管理器,你可以通过一行命令安装某一个软件包,然后软件包管理器会帮助你从软件 ...

随机推荐

  1. PAT团体程序设计大赛---(模拟)

    L1-1 古风排版(20 分) 中国的古人写文字,是从右向左竖向排版的.本题就请你编写程序,把一段文字按古风排版. 输入格式: 输入在第一行给出一个正整数N(<100),是每一列的字符数.第二行 ...

  2. CORS服务端跨域

    跨域,通常情况下是说在两个不通过的域名下面无法进行正常的通信,或者说是无法获取其他域名下面的数据,这个主要的原因是,浏览器出于安全问题的考虑,采用了同源策略,通过浏览器对JS的限制,防止恶意用户获取非 ...

  3. word使用宏 在文章中插入源代码进行排版

    1.宏的代码如下. Sub 设置代码表格() ' author: code4101 ' 设置代码表格 宏 ' ' ' 背景色为morning的配色方案,RGB为(229,229,229) ) With ...

  4. 搭建eova开发环境

    1.安装好maven 2.下载Eova项目解压到文件夹eova下 3.dos命令到eova文件夹下执行mvn eclipse:eclipse(注:构建eclipse项目命令) 4.修改*.tag文件错 ...

  5. JS遮罩层弹框效果

    对于前端开发者来说,js是不可缺少的语言.现在我开始把我日常积累的一些js效果或者通过搜索自己总结的一些效果分享给大家,希望能够帮助大家一起进步,也希望大家能够多多支持! 1.今天我先分享一个遮罩层弹 ...

  6. Substrings(hdu 4455)

    题意: 给定一个序列ai,个数为n.再给出一系列w:对于每个w,求序列中,所有长度为w的连续子串中的权值和,子串权值为子串中不同数的个数. /* dp[i]表示长度为i的序列不同元素个数之和. 考虑从 ...

  7. Gradle体验/第一篇:下装、安装、配置、体验

    http://jingyan.baidu.com/article/4d58d541167bc69dd4e9c009.html

  8. #error#学习方法,如何避免初始化错误

    #error#学习方法,如何避免初始化错误.错误来自:本博客的另一篇文章Demo示例程序源代码: ,01-导航实例-QQ空间.xcodeproj - CYLLoginViewController.mD ...

  9. elasticsearch.helpers.ScanError: Scroll request has only succeeded on xx shards

    # 当index=''为空时出现此错误

  10. shell命令行混合进制计算器smartbc

    需要简单的计算的时候,不想用GUI的计算器,能在shell下直接计算就最好了 查了下,有个东西叫 bc,  具体的使用就不赘述了,可以运行bc,然后进去计算,也可以echo传递过去,大概是像这样 ec ...