我的認爲這道題很不友好,由於思路不清晰調了很久。node
這道題實際上就是求一棵樹的帶權重心,很顯然一個點越遠離帶權重心,權值和就會越大。ios
那麼咱們先說一下暴力的思路,假設當前點爲x,若是存在一個點y,權值和小於x,那麼就向y這個方向轉移,直到與x相鄰的點中沒有權值和比x小的,那麼此時的x就是答案。算法
這種作法是$O(n^{2})$的,顯然過不了全部的數據,考慮優化。優化
考慮動態點分,假設咱們每次都從根節點x來搜索答案,那麼若是當前點不是答案,那麼與當前點相鄰的點中,必定存在答案比當前點小的點y,並且這個點若存在就是惟一存在。ui
那麼咱們找到y所在子樹的重心z,繼續從z開始作就好。spa
因爲點分樹的深度最深爲logn,因此這種算法有複雜度保證。code
注意:這道題普通的RMQ求LCA過不了,會超時,要用查詢複雜度爲$O(1)$的歐拉序LCA。blog
1 //Never forget why you start 2 #include<iostream> 3 #include<cstdio> 4 #include<cstdlib> 5 #include<cstring> 6 #include<cmath> 7 #include<algorithm> 8 #define inf (2147483647) 9 using namespace std; 10 typedef long long lol; 11 int n,m,lim; 12 struct node{ 13 int next,to; 14 lol dis; 15 }edge[200005]; 16 int head[100005],size; 17 void putin(int from,int to,lol dis){ 18 size++; 19 edge[size].next=head[from]; 20 edge[size].to=to; 21 edge[size].dis=dis; 22 head[from]=size; 23 } 24 int place[100005],dfscnt,st[200005][21],dfn,o[100005]; 25 lol dis[100005]; 26 void dfs1(int r,int father){ 27 int i,s=++dfn; 28 st[++dfscnt][0]=s; 29 o[s]=r; 30 place[r]=dfscnt; 31 for(i=head[r];i!=-1;i=edge[i].next){ 32 int y=edge[i].to; 33 if(y!=father){ 34 dis[y]=dis[r]+edge[i].dis; 35 dfs1(y,r); 36 st[++dfscnt][0]=s; 37 } 38 } 39 } 40 void make(){ 41 lim=log(n*2)/log(2); 42 for(int i=1;i<=lim;i++) 43 for(int j=1;j<=dfscnt;j++) 44 if(j+(1<<i)-1<=dfscnt) 45 st[j][i]=min(st[j][i-1],st[j+(1<<(i-1))][i-1]); 46 } 47 int LCA(int x,int y){ 48 if(place[x]>place[y])swap(x,y); 49 int lg=log(place[y]-place[x]+1)/log(2); 50 return o[min(st[place[x]][lg],st[place[y]-(1<<lg)+1][lg])]; 51 } 52 lol dist(int x,int y){ 53 int lca=LCA(x,y); 54 return dis[x]+dis[y]-dis[lca]*2; 55 } 56 int vis[100005],cnt[100005],d[100005],tot,root,ff[100005]; 57 void getroot(int r,int father){ 58 int i; 59 cnt[r]=1;d[r]=0; 60 for(i=head[r];i!=-1;i=edge[i].next){ 61 int y=edge[i].to; 62 if(!vis[y]&&y!=father){ 63 getroot(y,r); 64 cnt[r]+=cnt[y]; 65 d[r]=max(d[r],cnt[y]); 66 } 67 } 68 d[r]=max(d[r],tot-cnt[r]); 69 if(d[root]>d[r])root=r; 70 } 71 void buildtree(int r,int father){ 72 int i,all=tot; 73 vis[r]=1;ff[r]=father; 74 for(i=head[r];i!=-1;i=edge[i].next){ 75 int y=edge[i].to; 76 if(!vis[y]){ 77 if(cnt[y]>cnt[r])cnt[y]=all-cnt[r];tot=cnt[y]; 78 root=0;getroot(y,r);buildtree(root,r); 79 } 80 } 81 } 82 lol p[100005][2]; 83 void insert(int x,int v){ 84 int i; 85 for(i=x;ff[i];i=ff[i]){ 86 lol len=dist(x,ff[i]); 87 p[i][1]+=len*v; 88 p[ff[i]][0]+=len*v; 89 } 90 for(i=x;i;i=ff[i])cnt[i]+=v; 91 } 92 lol query(int x){ 93 int i; 94 lol ans=p[x][0]; 95 for(i=x;ff[i];i=ff[i]){ 96 lol len=dist(x,ff[i]); 97 ans+=p[ff[i]][0]; 98 ans+=len*(cnt[ff[i]]-cnt[i]); 99 ans-=p[i][1]; 100 } 101 return ans; 102 } 103 lol find(int r,lol ans){ 104 int i,to=0; 105 vis[r]=1; 106 for(i=head[r];i!=-1;i=edge[i].next){ 107 int y=edge[i].to; 108 lol tmp=query(y); 109 if(tmp<ans){to=y;break;} 110 } 111 if(to){ 112 for(i=to;ff[i]!=r;i=ff[i]); 113 ans=query(i); 114 ans=find(i,ans); 115 return ans; 116 } 117 else return ans; 118 } 119 void clean(){ 120 memset(head,-1,sizeof(head)); 121 size=0; 122 } 123 int read(){ 124 int ans=0,f=1;char i=getchar(); 125 while(i<'0'||i>'9'){if(i=='-')f=-1;i=getchar();} 126 while(i>='0'&&i<='9'){ans=ans*10+i-'0';i=getchar();} 127 return ans*f; 128 } 129 int main(){ 130 freopen("zjoi15_tree.in","r",stdin); 131 freopen("zjoi15_tree.out","w",stdout); 132 clean(); 133 int i,j; 134 n=read();m=read(); 135 for(i=1;i<n;i++){ 136 int u,v;lol l; 137 u=read();v=read();l=read(); 138 putin(u,v,l); 139 putin(v,u,l); 140 } 141 dfs1(1,0);make(); 142 tot=n;root=0;d[0]=inf; 143 getroot(1,0);buildtree(root,0); 144 for(i=1;i<=n;i++)if(!ff[i]){root=i;break;} 145 memset(cnt,0,sizeof(cnt)); 146 while(m--){ 147 int x,v; 148 x=read();v=read(); 149 insert(x,v); 150 printf("%lld\n",find(root,p[root][0])); 151 } 152 return 0; 153 }