タイトル説明:
N-1個のエッジが0のツリーの各ポイントの初期重みを与え、各エッジはa [i] -b [i]
を接続し、q個の操作(2つのタイプ)を与えます。
-
すべてのポイントをトラバースするための開始点としてa [i]を取り、パスはb [i]を通過できません。パス上のすべてのポイントに、wを追加します。
-
すべてのポイントをトラバースするための開始点として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;
}