题意:给你一颗树,每个结点的儿子数不超过2。每个结点有一个权值,一个结点的代价被定义为将其子树中所有结点的权值放入数组排序后,每个权值乘以其下标的和。让你计算所有结点的代价。
二叉树的条件没有用到。
每个结点开一个Splay,从叶子往上启发式合并上去,可以先bfs一遍确定合并顺序。每一次将Splay大小较小的结点的权值全提取出来塞到较大的里面。
由于权值可能重复出现,所以每个结点记个cnt。
答案统计的时候,就将那个刚塞进去的旋到根,然后答案加上左子树的权值和,再加上(右子树的权值的个数+该结点的cnt)*该结点的权值。
然后将较大儿子的Splay的根丢给父亲。
不必要进行内存回收,通过计算,所开的空间只要达到nlogn即可,实际上100w足够了。
#include<cstdio> #include<set> #include<queue> #include<cstring> #include<algorithm> using namespace std; typedef long long ll; const int maxn=1000000; ll sum[maxn]; int fa[maxn],val[maxn],c[maxn][2],root,tot,siz[maxn],cnt[maxn]; void Maintain(int x) { siz[x]=siz[c[x][0]]+siz[c[x][1]]+cnt[x]; sum[x]=sum[c[x][0]]+sum[c[x][1]]+(ll)val[x]*(ll)cnt[x]; } void NewNode(int &x,int Fa,int key) { x=++tot; fa[x]=Fa; c[x][0]=c[x][1]=0; val[x]=key; siz[x]=cnt[x]=1; } void Rotate(int x,bool flag) { int y=fa[x]; c[y][!flag]=c[x][flag]; fa[c[x][flag]]=y; if(fa[y]){ c[fa[y]][c[fa[y]][1]==y]=x; } fa[x]=fa[y]; c[x][flag]=y; fa[y]=x; Maintain(y); } void Splay(int &root,int x,int goal) { if(!x){ return; } int y; while((y=fa[x])!=goal){ if(fa[y]==goal){ Rotate(x,c[y][0]==x); } else{ if((c[y][0]==x)==(c[fa[y]][0]==y)){ Rotate(y,c[fa[y]][0]==y); } else{ Rotate(x,c[y][0]==x); y=fa[x]; } Rotate(x,c[y][0]==x); } } Maintain(x); if(!goal){ root=x; } } int Find(int key,int x) { while(c[x][val[x]<key]){ if(val[x]==key){ return x; } x=c[x][val[x]<key]; } return x; } void Insert(int &root,int key) { int x=Find(key,root); if(val[x]==key){ ++cnt[x]; Splay(root,x,0); return; } NewNode(c[x][val[x]<key],x,key); Splay(root,c[x][val[x]<key],0); } int roots[100005]; ll anss[100005]; bool vis[100005]; int e,first[100005],nex[200005],v[200005]; int dep[100005]; void AddEdge(int U,int V){ v[++e]=V; nex[e]=first[U]; first[U]=e; } int T,n,a[100005],b[100005]; bool cmp(const int &a,const int &b){ return siz[roots[a]]>siz[roots[b]]; } int sons[100005],BI; void dfs(int U){ for(int i=1;i<=cnt[U];++i){ Insert(roots[sons[1]],val[U]); int X=Find(val[U],roots[sons[1]]); Splay(roots[sons[1]],X,0); if(c[X][0]){ anss[BI]+=sum[c[X][0]]; } anss[BI]+=(ll)(cnt[X]+(c[X][1] ? siz[c[X][1]] : 0))*(ll)val[U]; } if(c[U][0]){ dfs(c[U][0]); } if(c[U][1]){ dfs(c[U][1]); } } int main(){ // freopen("a.in","r",stdin); // freopen("a.out","w",stdout); scanf("%d",&T); int x,y; for(;T;--T){ memset(first,0,sizeof(first)); e=0; scanf("%d",&n); for(int i=1;i<=n;++i){ scanf("%d",&a[i]); } for(int i=1;i<n;++i){ scanf("%d%d",&x,&y); AddEdge(x,y); AddEdge(y,x); } memset(vis,0,sizeof(vis)); memset(dep,0,sizeof(dep)); memset(anss,0,sizeof(anss)); queue<int>q; q.push(1); int t=0; while(!q.empty()){ int U=q.front(); q.pop(); vis[U]=1; b[++t]=U; for(int i=first[U];i;i=nex[i]){ if(!vis[v[i]]){ dep[v[i]]=dep[U]+1; q.push(v[i]); } } } for(int i=t;i>=1;--i){ BI=b[i]; int dir_son=0; for(int j=first[b[i]];j;j=nex[j]){ if(dep[v[j]]>dep[b[i]]){ sons[++dir_son]=v[j]; } } if(!dir_son){ NewNode(roots[b[i]],0,a[b[i]]); anss[b[i]]=a[b[i]]; continue; } sort(sons+1,sons+dir_son+1,cmp); anss[b[i]]=anss[sons[1]]; for(int j=2;j<=dir_son;++j){ dfs(roots[sons[j]]); } Insert(roots[sons[1]],a[b[i]]); int X=Find(a[b[i]],roots[sons[1]]); Splay(roots[sons[1]],X,0); if(c[X][0]){ anss[BI]+=sum[c[X][0]]; } anss[BI]+=(ll)(cnt[X]+(c[X][1] ? siz[c[X][1]] : 0))*(ll)a[b[i]]; roots[b[i]]=roots[sons[1]]; } for(int i=1;i<=n;++i){ printf("%lld ",anss[i]); } puts(""); memset(sum,0,sizeof(ll)*(tot+1)); memset(fa,0,sizeof(int)*(tot+1)); memset(val,0,sizeof(int)*(tot+1)); for(int i=0;i<=tot;++i){ c[i][0]=c[i][1]=0; } memset(siz,0,sizeof(int)*(tot+1)); memset(cnt,0,sizeof(int)*(tot+1)); memset(roots,0,sizeof(int)*(tot+1)); // printf("%d\n",tot); tot=0; } return 0; }
时间: 2024-11-05 04:51:28