hdu 6133 Army Formations(树状数组+启发式合并)
题意:
搞了一圈,最近就是让你输出每个点的答案,每个点的答案计算为将一该点为子树的全部的点的权值排序,求一下前缀和的前缀和。
题解:
由于是求前缀和的前缀和,考虑用树状数组,对于每插入一个数x,他的贡献为sum(x-1)+当前比他大的个数*x。
那么如果求树上每一个点的答案。
由于该树是一棵二叉树,所以我们先遍历每个节点的轻儿子(子节点数较小的儿子),再遍历重儿子,这样可以将节点数小的合并到大的。
然后总复杂度就是nlogn2
1 #include<bits/stdc++.h> 2 #define mst(a,b) memset(a,b,sizeof(a)) 3 #define F(i,a,b) for(int i=a;i<=b;++i) 4 using namespace std; 5 typedef long long ll; 6 7 const int N=1e5+7; 8 int t,n,a[N],hsh[N],h_ed,x,y,size[N],S[N],top; 9 ll sum[N],num[N],ans[N]; 10 vector<int>g[N]; 11 int tr[N][2],rnk[N]; 12 13 void dfs(int x,int fa) 14 { 15 size[x]=1; 16 for(int it:g[x])if(it!=fa) 17 dfs(it,x),size[x]+=size[it]; 18 for(int it:g[x])if(it!=fa) 19 { 20 if(size[tr[x][1]]<size[it])tr[x][1]=it; 21 if(size[tr[x][0]]<size[tr[x][1]])swap(tr[x][0],tr[x][1]); 22 } 23 } 24 25 inline void add(ll *C,int x,int v){while(x<=h_ed)C[x]+=v,x+=x&-x;} 26 inline ll ask(ll *C,int x){ll an=0;while(x)an+=C[x],x-=x&-x;return an;} 27 28 ll insert(int idx) 29 { 30 ll val=0; 31 add(num,rnk[idx],1),add(sum,rnk[idx],a[idx]); 32 val+=(ll)a[idx]*(ask(num,h_ed)-ask(num,rnk[idx]-1)); 33 val+=ask(sum,rnk[idx]-1); 34 return val; 35 } 36 37 void remove(int idx) 38 { 39 add(num,rnk[idx],-1),add(sum,rnk[idx],-a[idx]); 40 } 41 42 void dfs2(int x=1) 43 { 44 int l=top+1,r; 45 if(tr[x][0])dfs2(tr[x][0]); 46 r=top; 47 if(tr[x][1]) 48 { 49 F(i,l,r)remove(S[i]); 50 dfs2(tr[x][1]); 51 ans[x]=ans[tr[x][1]]; 52 F(i,l,r)ans[x]+=insert(S[i]); 53 } 54 else ans[x]=ans[tr[x][0]]; 55 S[++top]=x,ans[x]+=insert(x); 56 } 57 58 int main(){ 59 scanf("%d",&t); 60 while(t--) 61 { 62 scanf("%d",&n),top=0; 63 mst(sum,0),mst(num,0),mst(tr,0),mst(ans,0); 64 F(i,0,n)g[i].clear(); 65 F(i,1,n)scanf("%d",a+i),hsh[i]=a[i]; 66 sort(hsh+1,hsh+1+n),h_ed=unique(hsh+1,hsh+1+n)-hsh-1; 67 F(i,1,n)rnk[i]=lower_bound(hsh+1,hsh+1+h_ed,a[i])-hsh; 68 F(i,2,n) 69 { 70 scanf("%d%d",&x,&y); 71 g[x].push_back(y); 72 g[y].push_back(x); 73 } 74 dfs(1,0),dfs2(); 75 F(i,1,n)printf("%lld ",ans[i]); 76 puts(""); 77 } 78 return 0; 79 }