线段树合并 || BZOJ 5457: 城市
题面:https://www.lydsy.com/JudgeOnline/problem.php?id=5457
题解:
线段树合并,对于每个节点维护sum(以该节点为根的子树中最大的种类和)和kind(以该节点为根的子树中种类和最大的种类)即可。
代码:
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 using namespace std; 6 const int maxn=(4e5)+50; 7 int N,M,U,V,num_edge=0,edge_head[maxn],root[maxn]; 8 int num_treenode=0; 9 struct Edge{int to,nx;}edge[maxn<<1]; 10 inline void Add_edge(int from,int to){ 11 edge[++num_edge].nx=edge_head[from]; 12 edge[num_edge].to=to; 13 edge_head[from]=num_edge; 14 return; 15 } 16 struct Tree{int lc,rc,l,r,sum,kd;}tr[maxn*20]; 17 inline void Pushup(int x){ 18 int lc=tr[x].lc,rc=tr[x].rc; 19 if(tr[lc].sum>=tr[rc].sum){ 20 tr[x].sum=tr[lc].sum; 21 tr[x].kd=tr[lc].kd; 22 } 23 else { 24 tr[x].sum=tr[rc].sum; 25 tr[x].kd=tr[rc].kd; 26 } 27 return; 28 } 29 inline void Build(int x,int l,int r,int q,int s){ 30 tr[x].l=l;tr[x].r=r;int mid=(l+r)>>1; 31 if(l==r&&l==q){ 32 tr[x].kd=q; 33 tr[x].sum=s; 34 return; 35 } 36 if(q<=mid)Build(tr[x].lc=++num_treenode,l,mid,q,s); 37 else Build(tr[x].rc=++num_treenode,mid+1,r,q,s); 38 Pushup(x); 39 return; 40 } 41 struct A_{int kd,sum;}A[maxn]; 42 inline int Merge(int u,int v){ 43 if(!u)return v; 44 if(!v)return u; 45 int l=tr[u].l,r=tr[u].r; 46 if(l==r){ 47 tr[u].sum+=tr[v].sum; 48 return u; 49 } 50 tr[u].lc=Merge(tr[u].lc,tr[v].lc); 51 tr[u].rc=Merge(tr[u].rc,tr[v].rc); 52 Pushup(u); 53 return u; 54 } 55 inline void Dfs(int x,int fa){ 56 for(int i=edge_head[x];i;i=edge[i].nx){ 57 int y=edge[i].to; 58 if(y!=fa){ 59 Dfs(y,x); 60 Merge(root[x],root[y]); 61 } 62 } 63 return; 64 } 65 int main(){ 66 scanf("%d%d",&N,&M); 67 for(int i=1;i<N;i++){ 68 scanf("%d%d",&U,&V); 69 Add_edge(U,V);Add_edge(V,U); 70 } 71 for(int i=1;i<=N;i++){ 72 scanf("%d%d",&A[i].kd,&A[i].sum); 73 Build(root[i]=++num_treenode,1,M,A[i].kd,A[i].sum); 74 } 75 Dfs(1,0); 76 for(int i=1;i<=N;i++)printf("%d %d\n",tr[root[i]].kd,tr[root[i]].sum); 77 return 0; 78 }
By:AlenaNuna