abc187 --E-スルーパス(ツリーの違い)/ツリーチェーン分割+線分ツリー

タイトル説明:


N-1個のエッジが0のツリーの各ポイントの初期重みを与え、各エッジはa [i] -b [i]
接続し、q個の操作(2つのタイプ)を与えます。

  1. すべてのポイントをトラバースするための開始点としてa [i]を取り、パスはb [i]を通過できません。パス上のすべてのポイントに、wを追加します。

  2. すべてのポイントをトラバースするための開始点としてb [i]を取り、パスはa [i]を通過できません。パス上のすべてのポイントに、wを追加します。

質問のアイデア(解決策1):

二つの動作は基本的に同じであるが、出発点が異なっている。
出発点は、Uの場合、通過することができない点がVである。
場合、DEPは、[U] <DEP [V]を除くすべての点にwを追加することですvのサブツリー。dep[u]> dep [v]の
場合は、uのサブツリーにwを追加するだけです。

具体操作:

最初の前処理各ノードの深さは、
ルートノードが1であると仮定すると、
その後のためにDEP [U] <DEP [V] 我々は、[1] + = W、次いで減算NUM NUMであることがツリー全体にwを追加しますV、Wに移動
するためのDEP [U]> DEP [V] NUM [U] + = Wを

コード:

ll  n,q,fa[maxn],num[maxn],a[maxn],b[maxn],ans[maxn],dep[maxn];
vector<ll>e[maxn];
void pre_work(int u,int p) {
    
    
	fa[u] = p ,	dep[u] = dep[p]+1;
	for(int v:e[u]) if(v!=p) pre_work(v,u);
}
void dfs(int  u,int  p,ll  s) {
    
    
	s+=num[u];
	ans[u] = s;
	for(int v:e[u]) {
    
    
		if(v==p) continue;
		dfs(v,u,s);
	}
}
int main() {
    
    
	n=read();
	for(int i=1 ; i<=n-1 ; i++) {
    
    
		int u = read();
		int v = read();
		a[i]=u,b[i]=v;
		e[u].push_back(v);
		e[v].push_back(u);
	}
	pre_work(1,0);
	q=read();
	while(q--) {
    
    
		int t = read();
		int id = read(),u,v;
		ll w = read();
		u=a[id],v=b[id];
		if(t==2) swap(u,v);
		if(dep[u]>dep[v]) num[u]+=w;
		else num[1]+=w,num[v]-=w;
	}
	dfs(1,0,0);
	rep(i,1,n) printf("%lld\n",ans[i]);
	return 0;
}

(解決策2)

dfsシーケンスの後に線分ツリーを使用することもできます。
ツリーセクションの後に線分ツリーを使用することもできます。ツリーセクションを練習します。コードが臭くて長いです。
シーケンスが変換された後、間隔が変更され、シングルポイントクエリ
コード:

ll  n,q,fa[maxn],a[maxn],b[maxn],dep[maxn];
ll son[maxn],size_s[maxn],top[maxn],id[maxn],idex,od[maxn];
vector<ll>e[maxn];
struct node {
    
    
	ll l,r,lz,sum;
} num[maxn*4];
void pre_work(int u,int p) {
    
    
	fa[u] = p,dep[u] = dep[p]+1;
	size_s[u] = 1;
	for(int v:e[u]) {
    
    
		if(v==p) continue;
		pre_work(v,u);
		size_s[u]+=size_s[v];
		if(son[u]==0||size_s[son[u]]<size_s[v]) son[u] = v;
	}
}

void work(int u,int top_v) {
    
    
	id[u] = ++idex;
	od[idex] = u;
	top[u] = top_v;
	if(son[u]==0) return ;
	work(son[u],top_v);
	for(int v:e[u]) {
    
    
		if(v==fa[u]||v==son[u]) continue;
		work(v,v);
	}
}
void push_up(int st) {
    
    
	num[st].sum = num[st*2].sum + num[st*2+1].sum;
}
void push_down(int st) {
    
    
	if(num[st].lz==0) return ;
	num[st*2].lz+=num[st].lz;
	num[st*2+1].lz+=num[st].lz;

	num[st*2].sum += (num[st*2].r - num[st*2].l+1)*num[st].lz;
	num[st*2+1].sum += (num[st*2+1].r - num[st*2+1].l+1)*num[st].lz;
	num[st].lz =0 ;
}
void build(int st,int l,int r) {
    
    
	num[st].l = l,num[st].r = r;
	if(l==r) {
    
    
		num[st].lz=	num[st].sum =0 ;
		return ;
	}
	int mid = (l+r)>>1;
	build(st*2,l,mid);
	build(st*2+1,mid+1,r);
	push_up(st);
}
void update(int st,int l,int r,int ql,int qr,ll w) {
    
    
	if(ql<=l&&qr>=r) {
    
    
		num[st].lz+=w;
		num[st].sum += (num[st].r-num[st].l+1)*w*1ll;
		return ;
	}
	int mid = (l+r)>>1;
	if(ql<=mid) update(st*2,l,mid,ql,qr,w);
	if(qr>mid) update(st*2+1,mid+1,r,ql,qr,w);
	push_up(st);
}
ll query(int st,int l,int r,int pos) {
    
    
	if(l==r) {
    
    
		return num[st].sum;
	}
	push_down(st);
	int mid = (l+r)>>1;
	if(pos<=mid) return query(st*2,l,mid,pos);
	else return query(st*2+1,mid+1,r,pos);
	push_up(st);
}
int main() {
    
    
	n=read();
	for(int i=1 ; i<=n-1 ; i++) {
    
    
		int u = read();
		int v = read();
		a[i]=u,b[i]=v;
		e[u].push_back(v);
		e[v].push_back(u);
	}
	pre_work(1,0);
	work(1,1);
	build(1,1,n);
	q=read();
	while(q--) {
    
    
		int t = read();
		int ei = read(),u,v;
		ll w = read();
		u=a[ei],v=b[ei];
		if(t==2) swap(u,v);
		if(dep[u]>dep[v]) {
    
    
			update(1,1,n,id[u],id[u]+size_s[u]-1,w);
		} else {
    
    
			update(1,1,n,id[v],id[v]+size_s[v]-1,-w);
			update(1,1,n,id[1],id[1]+size_s[1]-1,w);
		}
	}
	rep(i,1,n) printf("%lld\n",query(1,1,n,id[i]));

	return 0;
}

ここに画像の説明を挿入

おすすめ

転載: blog.csdn.net/wmy0536/article/details/112150106