树链剖分板子 彩虹评测求条
查看原帖
树链剖分板子 彩虹评测求条
858608
BreadCakeCheese楼主2024/7/28 18:56

喜提RE5 WA1 MLE3 AC2

提货码代码如下:

#include<bits/stdc++.h>
using namespace std;
#define ls rt<<1
#define rs rt<<1|1
const int N=1e5+10;
int n,m,r,mod,w[N]; //题中所给 
int idx,h[N],e[N],ne[N]; //链式前向星相关 
int dep[N],fa[N],size[N],son[N]; //dfs1相关
int cnt,id[N],wt[N],top[N]; //dfs2相关 
int tree[N<<2],tag[N<<2]; //线段树相关
void add(int u,int v){ //链式前向星加边 
	idx++;
	e[idx]=v;
	ne[idx]=h[u];
	h[u]=idx;
} 
void pushdown(int rt,int l,int r){
	if(!tag[rt]) return;
	tag[ls]+=tag[rt];
	tag[rs]+=tag[rt];
	int mid=l+r>>1;
	tree[ls]=(tree[ls]+tag[rt]*(mid-l+1))%mod;
	tree[rs]=(tree[rs]+tag[rt]*(r-mid))%mod;
	tag[rt]=0;
}
void build(int rt,int l,int r){ //线段树的建树操作 
	if(l==r){
		tree[rt]=wt[l]%mod;
		return;
	}
	int mid=l+r>>1;
	build(ls,l,mid);
	build(rs,mid+1,r);
	tree[rt]=(tree[ls]+tree[rs])%mod;
} 
void upd(int rt,int l,int r,int L,int R,int v){
	if(L<=l&&r<=R){
		tag[rt]+=v;
		tree[rt]+=v*(r-l+1);
		return;
	}
	pushdown(rt,l,r);
	int mid=l+r>>1;
	if(L<=mid) upd(ls,l,mid,L,R,v);
	if(R>mid) upd(rs,mid+1,r,L,R,v);
} 
int query(int rt,int l,int r,int L,int R){
	if(L<=l&&r<=R) return tree[rt];
	pushdown(rt,l,r);
	int mid=l+r>>1,res=0;
	if(L<=mid) res=(res+query(ls,l,mid,L,R))%mod;
	if(R>mid) res=(res+query(rs,mid+1,r,L,R))%mod;
	return res;
}
int queryRange(int x,int y){
	int ans=0;
	while(top[x]!=top[y]){ //不在一条链上 
		if(dep[top[x]]<dep[top[y]]) swap(x,y); //把x点改为所在链顶端的深度更深的那个点
		ans=(ans+query(1,1,n,id[top[x]],id[x]))%mod; //ans加上x点到x所在链顶端 这一段区间的点权和
		x=fa[top[x]]; //把x跳到x所在链顶端的那个点的上面一个点
	}
	if(dep[x]>dep[y]) swap(x,y); //x更深
	ans=(ans+query(1,1,n,id[x],id[y]))%mod; //再加上此时两个点的区间和 
	return ans;
}
void updRange(int x,int y,int v){
	v%=mod;
	while(top[x]!=top[y]){ //同上 
		if(dep[top[x]<dep[top[y]]]) swap(x,y);
		upd(1,1,n,id[top[x]],id[x],v);
		x=fa[top[x]];
	}
	if(dep[x]>dep[y]) swap(x,y);
	upd(1,1,n,id[x],id[y],v);
}
int querySon(int x){
	return query(1,1,n,id[x],id[x]+size[x]-1); //子树区间右端点为id[x]+size[x]-1
}
void updSon(int x,int v){
	upd(1,1,n,id[x],id[x]+size[x]-1,v);
}
void dfs1(int u,int f,int deep){ //当前节点,父亲和深度
	dep[u]=deep;
	fa[u]=f;
	size[u]=1; // 标记深度、父亲和子树大小
	int maxson=-1; //记录重儿子的儿子个数
	for(int i=h[u];i;i=ne[i]){
		int v=e[i];
	 	if(v==f) continue;
	 	dfs1(v,u,deep+1); //dfs其儿子 
	 	size[u]+=size[v];
	 	if(size[v]>maxson){ //更新重儿子 
	 		maxson=size[v];
	 		son[u]=v;
		 }
	} 
}
void dfs2(int u,int topf){ //当前节点和当前链最顶端的节点 
	id[u]=++cnt;
	wt[cnt]=w[u];
	top[u]=topf; //标记新编号、初始值和所在链顶端 
	if(!son[u]) return;
	dfs2(son[u],topf); //先处理重儿子
	for(int i=h[u];i;i=ne[i]){
		int v=e[i];
		if(v==fa[u]||v==son[u]) continue;
		dfs2(v,v); //再处理轻儿子 
	} 
}
int main(){
	scanf("%d %d %d %d",&n,&m,&r,&mod);
	for(int i=1;i<=n;i++) scanf("%d",&w[i]);
	for(int i=1;i<=n-1;i++){
		//建图 
		int a,b;
		scanf("%d %d",&a,&b);
		add(a,b);
		add(b,a);
	}
	dfs1(r,0,1);
	dfs2(r,r);
	build(1,1,n);
	while(m--){
		int op,x,y,z;
		cin>>op;
		if(op==1){
			scanf("%d %d %d",&x,&y,&z);
			updRange(x,y,z);
		}else if(op==2){
			scanf("%d %d",&x,&y);
			printf("%d\n",queryRange(x,y));
		}else if(op==3){
			scanf("%d %d",&x,&y);
			updSon(x,y);
		}else{
			scanf("%d",&x);
			printf("%d\n",querySon(x));
		}
	}
	return 0;
}

其中,如果把N定义为2e5+10会发生这样的事情: MLE->RE,不是很理解,题目给的范围是1e5啊,而且数组开大不是更占空间嘛

2024/7/28 18:56
加载中...