博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
BZOJ 1036: [ZJOI2008]树的统计Count(树链剖分)
阅读量:5268 次
发布时间:2019-06-14

本文共 2979 字,大约阅读时间需要 9 分钟。

第一次打树链剖分,也挺容易的嘛~~~,两次dfs后建线段树维护就行了~~~

CDOE:

1
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using
namespace
std;
#define maxn 30010
struct
edges{
    
int
to,next;
}edge[maxn*2];
int
next[maxn],l;
int
addedge(
int
from,
int
to){
    
edge[++l]=(edges){to,next[from]};
    
next[from]=l;
return
0;
}
int
dep[maxn],par[maxn],si[maxn],ch[maxn];
bool
b[maxn];
int
dfs(
int
u){
    
dep[u]=dep[par[u]]+1;
    
b[u]=0;
    
si[u]=1;
    
for
(
int
i=next[u];i;i=edge[i].next)
    
if
(b[edge[i].to]) { 
        
par[edge[i].to]=u;
        
dfs(edge[i].to);
        
si[u]+=si[edge[i].to];
        
if
(si[ch[u]]<si[edge[i].to]) ch[u]=edge[i].to;
    
}
    
return
0;
}
int
top[maxn],id[maxn],arr[maxn],pos[maxn];
int
ind,num;
int
heavy_edge(
int
x,
bool
flag){
    
if
(flag) top[++ind]=x;
    
id[x]=ind;
    
b[x]=0;
    
arr[pos[x]=++num]=x;
    
if
(ch[x]) heavy_edge(ch[x],0);
    
for
(
int
i=next[x];i;i=edge[i].next)
    
if
(b[edge[i].to]){
        
heavy_edge(edge[i].to,1);
    
}
    
return
0;
}
struct
node{
    
int
l,r,Max,Sum;
}t[maxn*4];
int
w[maxn];
int
buildtree(
int
x,
int
l,
int
r){
    
t[x].l=l;t[x].r=r;
    
if
(l==r) {t[x].Max=t[x].Sum=w[arr[l]];
return
0;}
    
buildtree(x<<1,l,(l+r)>>1);
    
buildtree((x<<1)+1,((l+r)>>1)+1,r);
    
t[x].Max=max(t[x<<1].Max,t[(x<<1)+1].Max);
    
t[x].Sum=t[x<<1].Sum+t[(x<<1)+1].Sum;
    
return
0;
}
int
n;
int
init(){
    
scanf
(
"%d"
,&n);
    
for
(
int
i=1;i<n;i++){
    
int
x,y;
    
scanf
(
"%d%d"
,&x,&y);
    
addedge(x,y);addedge(y,x);
    
}
    
memset
(b,
true
,
sizeof
(b));
    
dfs(1);
    
memset
(b,
true
,
sizeof
(b));
    
heavy_edge(1,1);
    
for
(
int
i=1;i<=n;i++)
scanf
(
"%d"
,w+i);
    
buildtree(1,1,n);
    
return
0;
}
int
change(
int
x,
int
y){
    
int
l=t[x].l,r=t[x].r;
    
if
(y<l||y>r)
return
0;
    
if
(l==r) {t[x].Max=t[x].Sum=w[arr[y]];
return
0;}
    
change(x<<1,y);change((x<<1)+1,y);
    
t[x].Max=max(t[x<<1].Max,t[(x<<1)+1].Max);
    
t[x].Sum=t[x<<1].Sum+t[(x<<1)+1].Sum;
    
return
0;
}
int
gmax(
int
x,
int
x1,
int
y1){
    
int
l=t[x].l,r=t[x].r;
    
if
(l>y1||r<x1)
return
-30002;
    
if
(l>=x1&&r<=y1)
return
(t[x].Max);
    
return
(max(gmax(x<<1,x1,y1),gmax((x<<1)+1,x1,y1)));
}
int
gsum(
int
x,
int
x1,
int
y1){
    
int
l=t[x].l,r=t[x].r;
    
if
(l>y1||r<x1)
return
0;
    
if
(l>=x1&&r<=y1)
return
(t[x].Sum);
    
return
(gsum(x<<1,x1,y1)+gsum((x<<1)+1,x1,y1));
}
int
MAX(
int
l,
int
r){
    
int
ans=-30001;
    
while
(1){
    
if
(dep[top[id[l]]]<dep[top[id[r]]]) swap(l,r);
    
if
(id[l]!=id[r]) {ans=max(ans,gmax(1,pos[top[id[l]]],pos[l]));l=par[top[id[l]]];}
    
else
{
if
(dep[l]<dep[r]) swap(l,r);ans=max(ans,gmax(1,pos[r],pos[l]));
return
ans;}
    
}
}
int
SUM(
int
l,
int
r){
    
int
ans=0;
    
while
(1){
    
if
(dep[top[id[l]]]<dep[top[id[r]]]) swap(l,r);
    
if
(id[l]!=id[r]) {ans+=gsum(1,pos[top[id[l]]],pos[l]);l=par[top[id[l]]];}
    
else
{
if
(dep[l]<dep[r]) swap(l,r);ans+=gsum(1,pos[r],pos[l]);
return
ans;}
    
}
}
int
m;
int
work(){
    
scanf
(
"%d"
,&m);
    
for
(
int
i=1;i<=m;i++) {
    
int
x,y;
char
s[10];
    
scanf
(
"%s%d%d"
,s,&x,&y);
    
if
(s[0]==
'C'
) {w[x]=y;change(1,pos[x]);}
    
if
(s[1]==
'M'
) {
printf
(
"%d\n"
,MAX(x,y));}
    
if
(s[1]==
'S'
) {
printf
(
"%d\n"
,SUM(x,y));}
    
}
    
return
0;
}
int
main(){
    
init();
    
work();
    
return
0;
}

 

转载于:https://www.cnblogs.com/New-Godess/p/4348960.html

你可能感兴趣的文章
用css3绘制你需要的几何图形
查看>>
对其他团队的项目的意见或建议
查看>>
iOS 项目的编译速度提高
查看>>
机房收费系统——报表
查看>>
How to unshelve many shelves at same time
查看>>
table中checkbox选择多行
查看>>
动态链接库
查看>>
Magento开发文档(三):Magento控制器
查看>>
使用Docker官方的Django包【转】
查看>>
SuperSocket 学习
查看>>
给培训学校讲解ORM框架的课件
查看>>
此实现不是 Windows 平台 FIPS 验证的加密算法的一部分
查看>>
性能调优攻略
查看>>
线段树模板讲解
查看>>
ie6解决png图片透明问题
查看>>
瞬间的永恒
查看>>
docker overlay网络实现
查看>>
2019-8-5 考试总结
查看>>
jquery javascript 回到顶部功能
查看>>
JS中实现字符串和数组的相互转化
查看>>