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

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

Description

  一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w。我们将以下面的形式来要求你对这棵树完成

一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 I
II. 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

Sample Output

4
1
2
2
10
6
5
6
5
16

————————————————————————————

这题就是典型的树上路径取max 路径求和 单点修改了

算法没什么好说的 写了三种写法

1——树链剖分(线段树版)

#include
#include
#include
using std::swap;const int M=50007;int read(){ int ans=0,f=1,c=getchar(); while(c<'0'||c>'9'){
if(c=='-') f=-1; c=getchar();} while(c>='0'&&c<='9'){ans=ans*10+(c-'0'); c=getchar();} return ans*f;}int max(int x,int y){
return x>y?x:y;}char ch[5];int n,m;int first[M],cnt=1;struct node{
int to,next;}e[2*M];void ins(int a,int b){e[++cnt]=(node){b,first[a]}; first[a]=cnt;}void insert(int a,int b){ins(a,b); ins(b,a);}int fa[M],sz[M],top[M],son[M],id[M],idp=1,dep[M];void f1(int x){ sz[x]=1; for(int i=first[x];i;i=e[i].next){ int now=e[i].to; if(now==fa[x]) continue; fa[now]=x; dep[now]=dep[x]+1; f1(now); sz[x]+=sz[now]; if(sz[now]>sz[son[x]]) son[x]=now; }}void f2(int x,int tp){ top[x]=tp; id[x]=idp++; if(son[x]) f2(son[x],tp); for(int i=first[x];i;i=e[i].next){ int now=e[i].to; if(now!=fa[x]&&now!=son[x]) f2(now,now); }}struct pos{
int l,r,sum,mx;}tr[4*M];void build(int x,int l,int r){ tr[x].l=l; tr[x].r=r; if(l==r) return ; int mid=(l+r)>>1; build(x<<1,l,mid); build(x<<1^1,mid+1,r);}void up(int x){ tr[x].sum=tr[x<<1].sum+tr[x<<1^1].sum; tr[x].mx=max(tr[x<<1].mx,tr[x<<1^1].mx);}void modify(int x,int s,int y){ if(tr[x].l==tr[x].r) return void(tr[x].sum=tr[x].mx=y); int mid=(tr[x].l+tr[x].r)>>1; if(mid>=s) modify(x<<1,s,y); else modify(x<<1^1,s,y); up(x);}int push_max(int x,int L,int R){ if(L<=tr[x].l&&tr[x].r<=R) return tr[x].mx; int mid=(tr[x].l+tr[x].r)>>1,ans=-1e8; if(L<=mid) ans=max(ans,push_max(x<<1,L,R)); if(R>mid) ans=max(ans,push_max(x<<1^1,L,R)); return ans;}int Qmax(int x,int y){ int ans=-1e8; while(top[x]!=top[y]){ if(dep[top[x]]
id[y]) swap(x,y); ans=max(ans,push_max(1,id[x],id[y])); return ans;}int push_sum(int x,int L,int R){ if(L<=tr[x].l&&tr[x].r<=R) return tr[x].sum; int mid=(tr[x].l+tr[x].r)>>1,sum=0; if(L<=mid) sum+=push_sum(x<<1,L,R); if(R>mid) sum+=push_sum(x<<1^1,L,R); return sum;}int Qsum(int x,int y){ int sum=0; while(top[x]!=top[y]){ if(dep[top[x]]
id[y]) swap(x,y); sum+=push_sum(1,id[x],id[y]); return sum;}int main(){ int x,y; n=read(); for(int i=1;i
View Code

2——树链剖分(zkw线段树版)

#include
#include
#include
using std::swap;const int M=50007;int read(){ int ans=0,f=1,c=getchar(); while(c<'0'||c>'9'){
if(c=='-') f=-1; c=getchar();} while(c>='0'&&c<='9'){ans=ans*10+(c-'0'); c=getchar();} return ans*f;}int max(int x,int y){
return x>y?x:y;}char ch[5];int n,m;int first[M],cnt=1;struct node{
int to,next;}e[2*M];void ins(int a,int b){e[++cnt]=(node){b,first[a]}; first[a]=cnt;}void insert(int a,int b){ins(a,b); ins(b,a);}int fa[M],sz[M],top[M],son[M],id[M],idp=1,dep[M];void f1(int x){ sz[x]=1; for(int i=first[x];i;i=e[i].next){ int now=e[i].to; if(now==fa[x]) continue; fa[now]=x; dep[now]=dep[x]+1; f1(now); sz[x]+=sz[now]; if(sz[now]>sz[son[x]]) son[x]=now; }}void f2(int x,int tp){ top[x]=tp; id[x]=idp++; if(son[x]) f2(son[x],tp); for(int i=first[x];i;i=e[i].next){ int now=e[i].to; if(now!=fa[x]&&now!=son[x]) f2(now,now); }}int ly,s[3*M],mx[3*M];void modify(int x,int w){ s[x+ly]=w; mx[x+ly]=w; for(x=(x+ly)>>1;x;x>>=1) s[x]=s[x<<1]+s[x<<1^1],mx[x]=max(mx[x<<1],mx[x<<1^1]);}int push_max(int l,int r){ int ans=-1e8; for(l=l+ly-1,r=r+ly+1;r-l!=1;l>>=1,r>>=1){ if(~l&1) ans=max(ans,mx[l^1]); if(r&1) ans=max(ans,mx[r^1]); } return ans;}int Qmax(int x,int y){ int ans=-1e8; while(top[x]!=top[y]){ if(dep[top[x]]
id[y]) swap(x,y); ans=max(ans,push_max(id[x],id[y])); return ans;}int push_sum(int l,int r){ int sum=0; for(l=l+ly-1,r=r+ly+1;r-l!=1;l>>=1,r>>=1){ if(~l&1) sum+=s[l^1]; if(r&1) sum+=s[r^1]; } return sum;}int Qsum(int x,int y){ int sum=0; while(top[x]!=top[y]){ if(dep[top[x]]
id[y]) swap(x,y); sum+=push_sum(id[x],id[y]); return sum;}int main(){ int x,y; n=read(); ly=1; while(ly<=n+2) ly<<=1; for(int i=1;i
View Code

3——lct(link-cut-tree)

#include
#include
#include
#define LL long longusing namespace std;const int M=50007;int read(){ int ans=0,f=1,c=getchar(); while(c<'0'||c>'9'){
if(c=='-') f=-1; c=getchar();} while(c>='0'&&c<='9'){ans=ans*10+(c-'0'); c=getchar();} return ans*f;}int n,m,c[M][2],fa[M],a[M],b[M];LL v[M],sum[M],mx[M];bool rev[M];bool isrt(int x){
return c[fa[x]][0]!=x&&c[fa[x]][1]!=x;}void up(int x){ if(!x) return ; mx[x]=v[x]; sum[x]=v[x]; int l=c[x][0],r=c[x][1]; if(l) mx[x]=max(mx[x],mx[l]),sum[x]+=sum[l]; if(r) mx[x]=max(mx[x],mx[r]),sum[x]+=sum[r];}void down(int x){ if(!rev[x]) return ; rev[x]=0; int l=c[x][0],r=c[x][1]; if(l) swap(c[l][0],c[l][1]),rev[l]^=1; if(r) swap(c[r][0],c[r][1]),rev[r]^=1;}void rotate(int x){ int y=fa[x],z=fa[y],l=0,r=1; if(c[y][1]==x) l=1,r=0; if(!isrt(y)) c[z][c[z][1]==y]=x; fa[y]=x; fa[x]=z; fa[c[x][r]]=y; c[y][l]=c[x][r]; c[x][r]=y; up(y); up(x);}int st[M],top=0,S;void splay(int x){ st[++top]=x; for(int i=x;!isrt(i);i=fa[i]) st[++top]=fa[i]; while(top) down(st[top--]); while(!isrt(x)){ int y=fa[x],z=fa[y]; if(!isrt(y)){ if(c[z][0]==y^c[y][0]==x) rotate(x); else rotate(y); } rotate(x); }}void acs(int x0){ for(int x=x0,y=0;x;splay(x),c[x][1]=y,up(x),y=x,x=fa[x]); splay(x0);}void mrt(int x){acs(x); swap(c[x][0],c[x][1]); rev[x]^=1;}void link(int x,int y){mrt(x); fa[x]=y;}void spl(int x,int y){mrt(x); acs(y);}int main(){ int x,y; n=read(); for(int i=1;i
View Code

 

转载于:https://www.cnblogs.com/lyzuikeai/p/7623160.html

你可能感兴趣的文章
《你必须知道的.NET》读后小结(4)
查看>>
Android 应用内存管理-onTrimMemory,onLowMemory
查看>>
AST语法结构树初学者完整教程
查看>>
【LibreOJ】#6354. 「CodePlus 2018 4 月赛」最短路 异或优化建图+Dijkstra
查看>>
Python---RabbitMQ的使用
查看>>
iOS下JS与OC互相调用(七)--Cordova 基础
查看>>
lc257. Binary Tree Paths
查看>>
Spring Boot 监控利器 —— Actutor
查看>>
Spring Boot 2.x整合Activiti工作流以及模型设计器(前后端分离 iview admin vue 集成activiti工作流 模型设计器 动态...
查看>>
SharePoint poweshell 无法识别命令
查看>>
图解vueVue响应式原理
查看>>
《麦肯锡教给我的写作武器》摘录
查看>>
关于互联网的小事--摘要
查看>>
设置grid行填充颜色为红色
查看>>
url参数中有+、空格、=、%、&、#等特殊符号的问题解决
查看>>
servlet方式通过Cookie记住登录时的用户名和密码
查看>>
Cisco无线AP上联口为trunk时无法注册故障处理
查看>>
c语言学习之基础知识点介绍(十八):几个修饰关键字和内存分区
查看>>
【Unity3D实战】摇摆直升机开发实战(二)
查看>>
DataContract
查看>>