计蒜客NOIP模拟D1T2
原題:
?
蒜頭君有一棵有根樹,樹的每一邊都有邊權,蒜頭君想知道任意兩點間最短距離之和為多少。另外,由于各種原因,蒜頭君的樹的邊的邊權會發生若干次改變,蒜頭君想讓你告訴他,每一次改變后,任意兩點間最短距離之和為多少?
輸入格式
第一行一個正整數?n,表示蒜頭君的樹上的結點個數。
接下來?n?1?行,每行兩個正整數x?i??,y?i??, x?i??表示i+1?號結點的父親結點的編號,保證其父結點編號小于自己編號。y?i???表示?i+1?號結點的父親結點與自己間邊的距離。
接下來一行一個整數?m,表示樹的邊權發生改變的次數。
接下來?m?行,每行兩個正整數?a,b,表示將?a結點與其父親結點之間的距離改為b,保證?a≥2。
輸出格式
先輸出一個整數,表示對于原始的樹任意兩點間最短距離之和。
接下來?m?行,每行輸出一個整數,表示每一次改變后,任意兩點間最短距離之和。
數據規模
?
樣例輸入
4 1 1 1 1 1 1 1 2 2樣例輸出
9 12?
開始在想LCA啥的[某個人氣急敗壞的要樹剖]但是肯定TLE
雖然研究了一道類似的題解
但最后還是自己寫出來了[類似的→hdu2376]
就是給一棵樹然后求任意兩點的最短距離之和。然后給m次修改重新求和。
方法是每一條邊的兩段的節點個數相乘[乘法原理]然后再乘上邊權。就是計算每條邊被經過的次數。
中間的邏輯一定要推理明白。這道題出題人還是很良心的。每次給的都是這條邊底下的節點,對于計算方便很多。
m次修改就很好計算了。將這條邊的邊權修改,把原來的減去再加上現在的即可。
這題因為寫反了一個循環所以爆零了。好憂傷。
但是只有經歷了爆零才能重獲新生吧。
不想多說了。上代碼hhhhh。
#include<cstdio> #include<algorithm> #include<cstring> using namespace std;int fa[100000]; long long sum[100000],bian[100000];int main() { int n,m,j,i,k,w,e,s; long long ans; scanf("%d",&n);for(i=2;i<=n;i++) { scanf("%d%lld",&fa[i],&bian[i]); sum[i]=1; } for(i=n;i>=2;i--)//這個循環要是逆序因為前面的要依賴后面的 { sum[fa[i]]+=sum[i]; }ans=0; for(i=1;i<=n;i++) { ans+=bian[i]*sum[i]*(n-sum[i]); } printf("%lld\n",ans);scanf("%d",&m); for(i=0;i<m;i++) { scanf("%d%d",&j,&k);ans-=bian[j]*sum[j]*(n-sum[j]); bian[j]=k; ans+=bian[j]*sum[j]*(n-sum[j]); printf("%lld\n",ans); } return 0; }?
轉載于:https://www.cnblogs.com/hanyuweining/p/10321989.html
總結
以上是生活随笔為你收集整理的计蒜客NOIP模拟D1T2的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: php基础知识整理
- 下一篇: 记录:通过SSH远程连接Ubuntu