BZOJ 1036 树的统计
来源:互联网 发布:91视频解析网站源码 编辑:程序博客网 时间:2024/04/30 14:07
Description
一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w。我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 III. QSUM u v: 询问从点u到点v的路径上的节点的权值和 注意:从点u到点v的路径上的节点包括u和v本身
Input
输入的第一行为一个整数n,表示节点的个数。接下来n – 1行,每行2个整数a和b,表示节点a和节点b之间有一条边相连。接下来n行,每行一个整数,第i行的整数wi表示节点i的权值。接下来1行,为一个整数q,表示操作的总数。接下来q行,每行一个操作,以“CHANGE u t”或者“QMAX u v”或者“QSUM u v”的形式给出。 对于100%的数据,保证1<=n<=30000,0<=q<=200000;中途操作中保证每个节点的权值w在-30000到30000之间。
Output
对于每个“QMAX”或者“QSUM”的操作,每行输出一个整数表示要求输出的结果。
Sample Input
4
1 2
2 3
4 1
4 2 1 3
12
QMAX 3 4
QMAX 3 3
QMAX 3 2
QMAX 2 3
QSUM 3 4
QSUM 2 1
CHANGE 1 5
QMAX 3 4
CHANGE 3 6
QMAX 3 4
QMAX 2 4
QSUM 3 4
1 2
2 3
4 1
4 2 1 3
12
QMAX 3 4
QMAX 3 3
QMAX 3 2
QMAX 2 3
QSUM 3 4
QSUM 2 1
CHANGE 1 5
QMAX 3 4
CHANGE 3 6
QMAX 3 4
QMAX 2 4
QSUM 3 4
Sample Output
4
1
2
2
10
6
5
6
5
16
1
2
2
10
6
5
6
5
16
最近一直在打模板题,表示BZOJ稍微有点技术含量的题目我都切不动的。。
弱不是我的错,身为一只蒟蒻,在BZOJ混实在是太危险了
题解:树链剖分的裸题
树链剖分的思想是:树上链分治,将树拆成一条一条的链,然后分治查询
定义重儿子为儿子中子树节点数最大的结点,其与父亲相连的链为重链
其余的为轻儿子,轻链同理。
查询时只需不断的将两个结点向上提,然后查询提上去的过程中的链
这是一个LCA的过程。
其中树链剖分需要dfs求出fa(父亲),son(重儿子),num(子树结点数),dep(深度,LCA要用)
然后我们需要将树上的结点映射到线段树上去,我们可以在这个过程顺便求出top(所在重链的祖先)
映射的顺序实际上就是将树上的每一条链完整的剖到线段树中
因为重链和轻链都不会超过logn,所以时间复杂度还是很低的
之后就是线段树的普通操作和LCA的查询
代码如下:
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=30010,Max=0x7fffffff/3;
int n,u,v,cnt,pos,m,a,b;
int h[maxn],cl[maxn],fa[maxn],son[maxn],dep[maxn],num[maxn],p[maxn];
int top[maxn],co[maxn];char s[10];
struct edge{
int to,next;
}G[maxn*2];
struct tree{
int max_,sum_;
}t[maxn*3];
void add(int x,int y){cnt++;G[cnt].to=y;G[cnt].next=h[x];h[x]=cnt;}
void dfs(int x,int f,int d){
fa[x]=f;dep[x]=d;num[x]=1;
for(int i=h[x];i;i=G[i].next){
int k=G[i].to;
if(k!=f){
dfs(k,x,d+1);num[x]+=num[k];
if(num[k]>num[son[x]])son[x]=k;
}
}return;
}
void getpos(int x,int f){
p[x]=++pos;top[x]=f;co[p[x]]=cl[x];
if(son[x]!=0)getpos(son[x],f);
for(int i=h[x];i;i=G[i].next){
int k=G[i].to;
if(k!=fa[x]&&k!=son[x])getpos(k,k);
}return;
}
void up(int o){
int ll=o<<1,rr=ll|1;
t[o].max_=max(t[ll].max_,t[rr].max_);
t[o].sum_=t[ll].sum_+t[rr].sum_;
}
void build(int o,int l,int r){
if(l==r){t[o].max_=t[o].sum_=co[l];return;}
int ll=o<<1,rr=ll|1,mid=(l+r)>>1;
build(ll,l,mid);build(rr,mid+1,r);
up(o);return;
}
void update(int o,int l,int r,int loc,int v){
if(l==r){t[o].max_=t[o].sum_=v;return;}
int ll=o<<1,rr=ll|1,mid=(l+r)>>1;
if(loc<=mid)update(ll,l,mid,loc,v);
else update(rr,mid+1,r,loc,v);
up(o);return;
}
int asksum(int o,int l,int r,int x,int y){
if(l>=x&&r<=y){return t[o].sum_;}
int ll=o<<1,rr=ll|1,mid=(l+r)>>1;
if(y<=mid)return asksum(ll,l,mid,x,y);
else if(x>mid)return asksum(rr,mid+1,r,x,y);
else return asksum(ll,l,mid,x,y)+asksum(rr,mid+1,r,x,y);
}
int askmax(int o,int l,int r,int x,int y){
if(l>=x&&r<=y){return t[o].max_;}
int ll=o<<1,rr=ll|1,mid=(l+r)>>1;
if(y<=mid)return askmax(ll,l,mid,x,y);
else if(x>mid)return askmax(rr,mid+1,r,x,y);
else return max(askmax(ll,l,mid,x,y),askmax(rr,mid+1,r,x,y));
}
int LCA(int x,int y){
int ans=0;
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])swap(x,y);
ans+=asksum(1,1,pos,p[top[x]],p[x]);
x=fa[top[x]];
}
if(dep[x]>dep[y])swap(x,y);
ans+=asksum(1,1,pos,p[x],p[y]);
return ans;
}
int lca(int x,int y){
int ans=-Max;
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])swap(x,y);
ans=max(ans,askmax(1,1,pos,p[top[x]],p[x]));
x=fa[top[x]];
}
if(dep[x]>dep[y])swap(x,y);
ans=max(ans,askmax(1,1,pos,p[x],p[y]));
return ans;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n-1;++i){
scanf("%d%d",&u,&v);
add(u,v);add(v,u);
}
for(int i=1;i<=n;++i)scanf("%d",&cl[i]);
dfs(1,-1,1);getpos(1,1);build(1,1,pos);
scanf("%d",&m);
for(int i=1;i<=m;++i){
scanf("%s",s);scanf("%d%d",&a,&b);
if(s[0]=='C')update(1,1,pos,p[a],b);
else if(s[1]=='S')printf("%d\n",LCA(a,b));
else printf("%d\n",lca(a,b));
}
return 0;
}
0 0
- Bzoj 1036 树的统计
- bzoj 1036 树的统计
- BZOJ 1036 树的统计
- BZOJ 1036 树的统计
- BZOJ 1036: [ZJOI2008]树的统计Count
- BZOJ 1036: [ZJOI2008]树的统计Count
- BZOJ 1036 树的统计 Count 树链剖分
- BZOJ 1036 树的统计 树链剖分
- 【BZOJ 1036】[ZJOI2008]树的统计Count
- bzoj 1036: [ZJOI2008]树的统计Count
- BZOJ-1036-树的统计Count
- BZOJ 1036 树的统计Count 树链剖分
- bzoj 1036[ZJOI] 树的统计
- BZOJ 1036 [ZJOI2008]树的统计Count
- BZOJ 1036: [ZJOI2008]树的统计Count
- BZOJ 1036 [ZJOI2008]树的统计Count
- bzoj 1036 [ZJOI2008]树的统计Count
- 【bzoj】1036: [ZJOI2008]树的统计Count
- 微信企业号开发:接收消息和事件
- Dapper,大规模分布式系统的跟踪系统
- Android中build target,minSdkVersion,targetSdkVersion,maxSdkVersion概念区分
- Andrew机器学习课程笔记(1)——梯度下降、逻辑回归
- win32和x64平台的切换
- BZOJ 1036 树的统计
- hdu5288 多校联合第一场第一题
- CentOS更改yum源与更新系统
- Hive安装以及部署(Ubuntu-MySql)
- 网站通用百度地图调用示例,只需填入座标和百度密钥即可。内容可自己更换。
- java 虚拟机的理解
- 《移动APP测试实战》
- Google 发布 Android 性能优化典范
- BZOJ 1001 狼抓兔子