- CF600E
- 给你一棵有n个点的树,树上每个节点都有一种颜色ci。
- 让你求每个点子树出现最多的颜色/编号的和
- dfs遍历树过程进行线段树(权值线段树)合并,线段树无需按照*2 *2+1的方式去联系父子关系, 可以用一个id
- 出现一个新的结点id++,这道题注意一下有多个数目相同的颜色时输出他们的和即可。线段树结点维护三个值,
- 这个点的答案,最多的颜色数目,与颜色种类。
-
#include<bits/stdc++.h> using namespace std; #define maxn 123456 #define ll long long #define lson tree[root].l #define rson tree[root].r int n,c[maxn],x,y,cnt,t; ll id,ok[maxn]; vector<int>gg[maxn]; struct node { int l,r; ll big,sum,ans; } tree[4000050]; void up(int root) { if(tree[lson].sum>tree[rson].sum) { tree[root].sum=tree[lson].sum; tree[root].big=tree[lson].big; tree[root].ans=tree[lson].ans; } else if(tree[lson].sum<tree[rson].sum) { tree[root].sum=tree[rson].sum; tree[root].big=tree[rson].big; tree[root].ans=tree[rson].ans; } else { tree[root].sum=tree[lson].sum; tree[root].big=tree[lson].big; tree[root].ans=tree[lson].ans+tree[rson].ans; } } int unon(int a,int b,int l,int r) { if(!a)return b; if(!b)return a; if(l==r) { tree[a].big=l; tree[a].sum+=tree[b].sum; tree[a].ans=l; return a; } int mid=(l+r)/2; tree[a].l=unon(tree[a].l,tree[b].l,l,mid); tree[a].r=unon(tree[a].r,tree[b].r,mid+1,r); up(a); return a; } void updata(int &root,int l,int r,int pos,int ad) { if(!root)root=++id; if(l==r) { tree[root].big=l; tree[root].sum+=ad; tree[root].ans=l; return ; } int mid=(l+r)/2; if(pos<=mid)updata(tree[root].l,l,mid,pos,ad); else updata(tree[root].r,mid+1,r,pos,ad); up(root); } void dfs(int cur,int fa) { for(int i=0; i<gg[cur].size(); i++) { int v=gg[cur][i]; if(v==fa)continue; dfs(v,cur); unon(cur,v,1,100000); } updata(cur,1,100000,c[cur],1); ok[cur]=tree[cur].ans; } int main() { scanf("%d",&n); id=n; for(int i=1; i<=n; i++) scanf("%d",&c[i]); for(int i=1; i<n; i++) { scanf("%d%d",&x,&y); gg[x].push_back(y); gg[y].push_back(x); } dfs(1,0); for(int i=1; i<=n; i++) { printf("%lld",ok[i]); if(i<n)printf(" "); else printf("\n"); } return 0; }
E. Lomsat gelral-CF600E-线段树合并
最新推荐文章于 2024-09-15 10:50:49 发布