重建 (树链剖分+线段树)

只是一个仅仅6KB的代码

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;

const int maxn = (int)1e5+10;

int N,Q,k,tot=0;
double xsum,xmin,xmax,count;

int head[maxn],dep[maxn],fa[maxn],hv[maxn],anc[maxn],size[maxn],id[maxn],L[maxn],R[maxn];

struct node{int v,next;}e[2*maxn];

struct tree{
	int l,r;
	double sum,min,max,col,re;
}t[4*maxn];

void adde(int u,int v){
	e[k].v=v; e[k].next=head[u]; head[u]=k++;
}


void pre_dfs(int u,int f,int dis){
	dep[u]=dis; fa[u]=f; hv[u]=-1; size[u]=1;
	int t=0;
	for(int i=head[u];i!=-1;i=e[i].next){
		int v=e[i].v;
		if(v==f)continue;
		pre_dfs(v,u,dis+1);
		size[u]+=size[v];
		if(size[v]>t){
			t=size[v]; hv[u]=v;
		}
	}
}

void dfs(int u,int x){
	anc[u]=x; id[u]=++tot; L[u]=tot;
	if(hv[u]!=-1)dfs(hv[u],x);
	for(int i=head[u];i!=-1;i=e[i].next){
		int v=e[i].v;
		if(v==fa[u] || v==hv[u])continue;
		dfs(v,v);
	}
	R[u]=tot;
}


void pushup(int x){
	t[x].sum=t[x<<1].sum+t[x<<1|1].sum;
	t[x].min=min(t[x<<1].min,t[x<<1|1].min);
	t[x].max=max(t[x<<1].max,t[x<<1|1].max);
}

void pushdown(int x){
	if(t[x].col==1){//col=1表示该次为变为相同的操作
		t[x<<1].min=t[x<<1].max=t[x<<1].re=t[x].re;
		t[x<<1].sum=(t[x<<1].r-t[x<<1].l+1)*t[x].re;
		
		t[x<<1|1].min=t[x<<1|1].max=t[x<<1|1].re=t[x].re;
		t[x<<1|1].sum=(t[x<<1|1].r-t[x<<1|1].l+1)*t[x].re;
		
		t[x<<1].col=t[x<<1|1].col=1;
		t[x].col=-1; t[x].re=0;
	}
	
	if(t[x].col==2){//col=2表示该次是增加的操作
		t[x<<1].min+=t[x].re; t[x<<1].max+=t[x].re; t[x<<1].re+=t[x].re;
		t[x<<1].sum+=(t[x<<1].r-t[x<<1].l+1)*t[x].re;
		
		t[x<<1|1].min+=t[x].re; t[x<<1|1].max+=t[x].re; t[x<<1|1].re+=t[x].re;
		t[x<<1|1].sum+=(t[x<<1|1].r-t[x<<1|1].l+1)*t[x].re;
		
		if(t[x<<1].col!=1)t[x<<1].col=2;
		if(t[x<<1|1].col!=1)t[x<<1|1].col=2;
		//t[x<<1].col=t[x<<1|1].col=2;
		t[x].col=-1; t[x].re=0; 
	}
}

void built(int x,int l,int r){
	t[x].l=l; t[x].r=r;
	if(l==r){
		t[x].col=-1; t[x].re=0; t[x].sum=0; t[x].min=0; t[x].max=0; return ; 
	}
	int mid=(l+r)>>1;
	built(x<<1,l,mid); built(x<<1|1,mid+1,r);
}

void modify(int x,int l,int r,double v){//make them to be the same.
	if(t[x].l>=l && t[x].r<=r){
		t[x].min=t[x].max=v;
		t[x].sum=v*(t[x].r-t[x].l+1);
		t[x].re=v; t[x].col=1;
		return ;
	}
	pushdown(x);
	int mid=(t[x].l+t[x].r)>>1;
	if(l<=mid)modify(x<<1,l,r,v);
	if(r> mid)modify(x<<1|1,l,r,v);
	pushup(x);
}

void improve(int x,int l,int r,double v){//add v to all nodes in this segment.
	if(t[x].l>=l && t[x].r<=r){
		t[x].sum+=(t[x].r-t[x].l+1)*v;
		t[x].min+=v; t[x].max+=v;
		t[x].re+=v;
		if(t[x].col!=1)t[x].col=2;
		return ;
	}
	pushdown(x);
	int mid=(t[x].l+t[x].r)>>1;
	if(l<=mid)improve(x<<1,l,r,v);
	if(r> mid)improve(x<<1|1,l,r,v);
	pushup(x);
}

void ask(int x,int l,int r){
	if(t[x].l>=l && t[x].r<=r){
		xsum+=t[x].sum; xmin=min(xmin,t[x].min); xmax=max(xmax,t[x].max);
		count+=t[x].r-t[x].l+1; return ;
	}
	pushdown(x);
	int mid=(t[x].l+t[x].r)>>1;
	if(l<=mid)ask(x<<1,l,r);
	if(r> mid)ask(x<<1|1,l,r);
	pushup(x);
}


void change(int x,int y,double v,int op){//1->F, 2->N,3->C
	int ux=anc[x],uy=anc[y];
	while(ux!=uy){
		if(dep[ux]>dep[uy]){
			swap(x,y); swap(ux,uy);
		}
		if(op==1)modify(1,id[uy],id[y],v);
		if(op==2)improve(1,id[uy],id[y],v);
		if(op==3)ask(1,id[uy],id[y]);
		y=fa[uy]; uy=anc[y];
	}
	
	if(dep[x]>dep[y])swap(x,y);
	if(op==1)modify(1,id[x],id[y],v);
	if(op==2)improve(1,id[x],id[y],v);
	if(op==3)ask(1,id[x],id[y]);
}

int main(){
	int T;
	while(scanf("%d",&T)==1){
		k=0;
		memset(head,-1,sizeof(head));
		
		scanf("%d%d",&N,&Q);
		for(int i=1;i<N;i++){
			int a,b; scanf("%d%d",&a,&b);
			adde(a,b); adde(b,a);
		}
		
		pre_dfs(1,-1,0);
		dfs(1,1);
		built(1,1,tot);
		
		char s[10];
		for(int i=1;i<=Q;i++){
			scanf("%s",s); int l=strlen(s);
			int a,b; double v;
			if(l==1){
				if(s[0]=='F'){
					scanf("%d%d",&a,&b);
					xsum=0; xmin=10000000000000000; xmax=0; count=0;
					change(a,b,0,3);
					change(a,b,xsum/count,1);
				}
				else if(s[0]=='N'){
					scanf("%d%d%lf",&a,&b,&v);
					change(a,b,v,2);
				}
				else {
					scanf("%d%d",&a,&b);
					xsum=0; xmin=10000000000000000; xmax=0; count=0;
					change(a,b,0,3);
					printf("%lf %lf %lf\n",xmin,xmax,xsum);
				}
			}
			else{
				if(s[1]=='F'){
					scanf("%d",&a);
					xsum=0; xmin=10000000000000000; xmax=0; count=0;
					ask(1,L[a],R[a]);
					modify(1,L[a],R[a],xsum/count);
				}
				else if(s[1]=='N'){
					scanf("%d%lf",&a,&v);
					improve(1,L[a],R[a],v);
				}
				else {
					scanf("%d",&a);
					xsum=0; xmin=10000000000000000; xmax=0; count=0;
					ask(1,L[a],R[a]);
					printf("%lf %lf %lf\n",xmin,xmax,xsum);
				}
			}
		}
	}
	return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值