洛谷 P2590 [ZJOI2008]树的统计

题目:树的统计

思路:树剖

参考:
吊打集训队的zcy的代码
几乎是照着抄的……

数据生成器:

#include<bits/stdc++.h>
using namespace std;

#define maxn 10
#define maxm 10
#define maxa 10
#define Rand() (rand()+rand()%19260817)

int fa[maxn+5]= {0};

int find(int x) {
	if(fa[x]==0) return x;
	return fa[x]=find(fa[x]);
}

int main() {
	srand(time(NULL));
	int n,m;
	n=Rand()%maxn+1;
	m=Rand()%maxm+1;
	printf("%d\n",n);
	for(int i=1; i<n; i++) {
		int l=0,r=0;
		while(find(l)==find(r)) {
			l=Rand()%n+1;
			r=n-Rand()%n;
		}
		int x=find(l),y=find(r);
		fa[x]=y;
		printf("%d %d\n",l,r);
	}
	for(int i=1; i<=n; i++) printf("%d ",Rand()%maxn+1);
	printf("\n%d\n",m);
	while(m--) {
		int opr=Rand()%3;
		if(opr==0) printf("QMAX ");
		if(opr==1) printf("QSUM ");
		if(opr==2) printf("CHANGE ");
		int l=1,r=0;
		l=Rand()%n+1;
		r=n-Rand()%n;
		printf("%d %d\n",l,r);
	}
	return 0;
}

代码:
有注释版:

using namespace std;

#define maxn 400000
#define inf (1<<30)

int n,m;
vector<int> g[maxn+5];	//原图 
int a[maxn+5]= {0};	//点权 

int d[maxn+5],fa[maxn+5]; //深度、父节点 
int sz[maxn+5],wson[maxn+5];	//子树节点个数,重儿子 

int pre[maxn+5]= {0};	//节点的新编号 
int top[maxn+5]= {0}; 	//新编号对应的节点 
int tpos[maxn+5]= {0}	//链顶的位置 
int cnt=0;	//计数器 

int maxv[maxn+5]= {0},sumv[maxn+5]= {0};	//区间最大值,区间和 

void push_up(int o,int lch,int rch) { 	//线段树上传信息 
	sumv[o]=sumv[lch]+sumv[rch];
	maxv[o]=max(maxv[lch],maxv[rch]);
}

void update(int o,int l,int r,int p,int v) {	//线段树单点修改 
	int mid=(r-l)/2+l;
	if(p<l||p>r) return ;
	if(l==r) {
		sumv[o]=maxv[o]=v;
		return ;
	}
	int lch=o*2,rch=lch+1;
	update(lch,l,mid,p,v),update(rch,mid+1,r,p,v);
	push_up(o,lch,rch);
}

void build(int o,int l,int r) {	//线段树建树 
	if(l==r) {
		sumv[o]=maxv[o]=a[pre[l]];
		return ;
	}
	int mid=(r-l)/2+l;
	int lch=o*2,rch=lch+1;
	build(lch,l,mid),build(rch,mid+1,r);
	push_up(o,lch,rch);
}

void readin() {	//读入 
	scanf("%d",&n);
	for(int i=1; i<n; i++) {
		int x,y;
		scanf("%d%d",&x,&y);
		g[x].push_back(y);
		g[y].push_back(x);
	}
	for(int i=1; i<=n; i++) scanf("%d",&a[i]);
	scanf("%d",&m);
}

int querymax(int o,int l,int r,int P,int Q) {	//线段树区间查询max 
	if(P<=l&&r<=Q) return maxv[o];
	else if(P>r||Q<l) return -inf;
	int mid=l+(r-l)/2;
	int lch=o*2,rch=lch+1;
	return max(querymax(lch,l,mid,P,Q),querymax(rch,mid+1,r,P,Q));
}

int querysum(int o,int l,int r,int P,int Q) {	//线段树区间查询sum
	if(P<=l&&r<=Q) return sumv[o];
	else if(P>r||Q<l) return 0;
	int mid=l+(r-l)/2;
	int lch=o*2,rch=lch+1;
	return querysum(lch,l,mid,P,Q)+querysum(rch,mid+1,r,P,Q);
}

int querym(int u,int v) {	//询问max 
	int ans=-inf;
	while(top[u]!=top[v]) {	//没走到LCA 
		if(d[top[u]]<d[top[v]]) swap(u,v);	//始终保证u的深度较大 
		ans=max(ans,querymax(1,1,n,tpos[top[u]],tpos[u]));
		u=fa[top[u]];
	}
	if(d[u]<d[v]) swap(u,v);
	ans=max(ans,querymax(1,1,n,tpos[v],tpos[u]));
	return ans;
}

int querys(int u,int v) {	//询问sum 
	int ans=0;
	while(top[u]!=top[v]) {
		if(d[top[u]]<d[top[v]]) swap(u,v);
		ans+=querysum(1,1,n,tpos[top[u]],tpos[u]);
		u=fa[top[u]];
	}
	if(d[u]<d[v]) swap(u,v);
	ans+=querysum(1,1,n,tpos[v],tpos[u]);
	return ans;
}

void dfs1(int x,int f) {	//处理sz[],d[],fs[],wson[] 
	sz[x]=1;
	for(int i=0; i<g[x].size(); i++) {
		int y=g[x][i];
		if(y==f) continue;
		d[y]=d[x]+1,fa[y]=x;
		dfs1(y,x);
		sz[x]+=sz[y];
		if(sz[y]>sz[wson[x]]) wson[x]=y;
	}
}

void dfs2(int x,int tp) {	//重新编号 
	tpos[x]=++cnt;
	pre[cnt]=x;
	top[x]=tp;
	if(wson[x]) {
		dfs2(wson[x],tp);
	}
	for(int i=0; i<g[x].size(); i++) {
		int y=g[x][i];
		if(y==fa[x]||y==wson[x]) continue;
		dfs2(y,y);
	}
}

int main() {
	readin();
	d[1]=1,fa[1]=1;	//默认1为根 
	dfs1(1,-1),dfs2(1,1);
	build(1,1,n);
	while(m--) {
		char s[10];
		int x,y;
		scanf("%s%d%d",s,&x,&y);
		if(s[1]=='H') {
			update(1,1,n,tpos[x],y);
		} else if(s[1]=='M') {
			printf("%d\n",querym(x,y));
		} else if(s[1]=='S') {
			printf("%d\n",querys(x,y));
		}
	}
	return 0;
}

无注释精简版:

#include<bits/stdc++.h>
using namespace std;

#define maxn 400000
#define inf (1<<30)

int n,m;
vector<int> g[maxn+5];
int a[maxn+5]= {0};

int d[maxn+5],fa[maxn+5];
int sz[maxn+5],wson[maxn+5];

int top[maxn+5]= {0};
int tpos[maxn+5]= {0},pre[maxn+5]= {0};
int cnt=0;

int maxv[maxn+5]= {0},sumv[maxn+5]= {0};

void push_up(int o,int lch,int rch) {
	sumv[o]=sumv[lch]+sumv[rch];
	maxv[o]=max(maxv[lch],maxv[rch]);
}

void update(int o,int l,int r,int p,int v) {
	int mid=(r-l)/2+l;
	if(p<l||p>r) return ;
	if(l==r) {
		sumv[o]=maxv[o]=v;
		return ;
	}
	int lch=o*2,rch=lch+1;
	update(lch,l,mid,p,v),update(rch,mid+1,r,p,v);
	push_up(o,lch,rch);
}

void build(int o,int l,int r) {
	if(l==r) {
		sumv[o]=maxv[o]=a[pre[l]];
		return ;
	}
	int mid=(r-l)/2+l;
	int lch=o*2,rch=lch+1;
	build(lch,l,mid),build(rch,mid+1,r);
	push_up(o,lch,rch);
}

void readin() {
	scanf("%d",&n);
	for(int i=1; i<n; i++) {
		int x,y;
		scanf("%d%d",&x,&y);
		g[x].push_back(y);
		g[y].push_back(x);
	}
	for(int i=1; i<=n; i++) scanf("%d",&a[i]);
	scanf("%d",&m);
}

void dfs1(int x,int f) {
	sz[x]=1;
	for(int i=0; i<g[x].size(); i++) {
		int y=g[x][i];
		if(y==f) continue;
		d[y]=d[x]+1,fa[y]=x;
		dfs1(y,x);
		sz[x]+=sz[y];
		if(sz[y]>sz[wson[x]]) wson[x]=y;
	}
}

void dfs2(int x,int tp) {
	tpos[x]=++cnt;
	pre[cnt]=x;
	top[x]=tp;
	if(wson[x]) {
		dfs2(wson[x],tp);
	}
	for(int i=0; i<g[x].size(); i++) {
		int y=g[x][i];
		if(y==fa[x]||y==wson[x]) continue;
		dfs2(y,y);
	}
}

int querymax(int o,int l,int r,int P,int Q) {
	if(P<=l&&r<=Q) return maxv[o];
	else if(P>r||Q<l) return -inf;
	int mid=l+(r-l)/2;
	int lch=o*2,rch=lch+1;
	return max(querymax(lch,l,mid,P,Q),querymax(rch,mid+1,r,P,Q));
}

int querym(int u,int v) {
	int ans=-inf;
	while(top[u]!=top[v]) {
		if(d[top[u]]<d[top[v]]) swap(u,v);
		ans=max(ans,querymax(1,1,n,tpos[top[u]],tpos[u]));
		u=fa[top[u]];
	}
	if(d[u]<d[v]) swap(u,v);
	ans=max(ans,querymax(1,1,n,tpos[v],tpos[u]));
	return ans;
}

int querysum(int o,int l,int r,int P,int Q) {
	if(P<=l&&r<=Q) return sumv[o];
	else if(P>r||Q<l) return 0;
	int mid=l+(r-l)/2;
	int lch=o*2,rch=lch+1;
	return querysum(lch,l,mid,P,Q)+querysum(rch,mid+1,r,P,Q);
}

int querys(int u,int v) {
	int ans=0;
	while(top[u]!=top[v]) {
		if(d[top[u]]<d[top[v]]) swap(u,v);
		ans+=querysum(1,1,n,tpos[top[u]],tpos[u]);
		u=fa[top[u]];
	}
	if(d[u]<d[v]) swap(u,v);
	ans+=querysum(1,1,n,tpos[v],tpos[u]);
	return ans;
}

int main() {
	readin();
	d[1]=1,fa[1]=1;
	dfs1(1,-1),dfs2(1,1);
	build(1,1,n);
	while(m--) {
		char s[10];
		int x,y;
		scanf("%s%d%d",s,&x,&y);
		if(s[1]=='H') {
			update(1,1,n,tpos[x],y);
		} else if(s[1]=='M') {
			printf("%d\n",querym(x,y));
		} else if(s[1]=='S') {
			printf("%d\n",querys(x,y));
		}
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值