[codeforces600E]Lomsat gelral(dsu on the tree+讲解)
来源:互联网 发布:淘宝有什么好的男装店 编辑:程序博客网 时间:2024/05/20 00:12
题目:
我是超链接
题意:
一棵树,每一个点有一个颜色,统计以每一个节点为根的子树中出现次数最多的颜色的编号和。
题解:
基本就是dsu的裸题啦,下面讲解见咯
代码:
#include <cstdio>#include <iostream>#include <cstring>#define LL long long#define N 100005using namespace std;int tot,nxt[N*2],point[N],v[N*2],size[N],son[N],cnt[N],a[N],maxx,Son;LL sum,ans[N];void addline(int x,int y){ ++tot; nxt[tot]=point[x]; point[x]=tot; v[tot]=y; ++tot; nxt[tot]=point[y]; point[y]=tot; v[tot]=x;}void getson(int x,int fa){ size[x]=1; for (int i=point[x];i;i=nxt[i]) if (v[i]!=fa) { getson(v[i],x); if (size[v[i]]>size[son[x]]) son[x]=v[i]; size[x]+=size[v[i]]; }}void add(int x,int fa,int vv){ cnt[a[x]]+=vv; if (cnt[a[x]]>maxx) sum=(LL)a[x],maxx=cnt[a[x]]; else if (cnt[a[x]]==maxx) sum+=(LL)a[x]; for (int i=point[x];i;i=nxt[i]) if (v[i]!=fa && v[i]!=Son) add(v[i],x,vv);}void dfs(int x,int fa,int k){ for (int i=point[x];i;i=nxt[i]) if (v[i]!=fa && v[i]!=son[x]) dfs(v[i],x,0); if (son[x])//不是叶子,有重儿子 dfs(son[x],x,1),Son=son[x]; add(x,fa,1);//是叶子||轻儿子就加入贡献,并不会删除贡献 Son=0; ans[x]=sum; if (!k) add(x,fa,-1),maxx=sum=0;//轻儿子 }int main(){ int n,i; scanf("%d",&n); for (i=1;i<=n;i++) scanf("%d",&a[i]); for (i=1;i<n;i++) { int x,y; scanf("%d%d",&x,&y); addline(x,y); } getson(1,0); dfs(1,0,0); for (i=1;i<=n;i++) printf("%lld ",ans[i]);}
普及向:
从优秀的学长学来的新姿势
什么是dsu on tree
dsu on tree用来解决这样一类问题:统计树上一个节点的子树中具有某种特征的节点数。
例如子树中颜色为x的个数。
这种方法可以做到O(nlogn)的复杂度。
那么dsu到底是个什么玩意呢?其实它的中文译名就是众所周知的并查集…
有的小朋友就会问了,并查集怎么跑到树上去的呢?
恩……其实说白了就是启发式合并:在做一类维护问题的时候,将size较小的合并到较大的size上,从而达到降低时间复杂度的目的。
又是并查集的按秩合并思想应用
一个例子
以上面的问题举个例子。
暴力
void add(int x,int fa,int vv){ cnt[a[x]]+=vv; if (cnt[a[x]]>maxx) sum=(LL)a[x],maxx=cnt[a[x]]; else if (cnt[a[x]]==maxx) sum+=(LL)a[x]; for (int i=point[x];i;i=nxt[i]) if (v[i]!=fa) add(v[i],x,vv);}void dfs(int x,int fa,int k){ sum=0,maxx=0; add(x,fa,1); ans[x]=sum; add(x,fa,-1); for (int i=point[x];i;i=nxt[i]) if (v[i]!=fa) dfs(v[i],x,0); }
代码简短也会T
在这种做法中,每次统计x节点前,暴力将x的子树的贡献加入,统计结束后,再暴力删除贡献,消除影响。
时间复杂度O(n^2)
但是这样有很多无用的删除操作,能不能减少这种操作呢。
树链剖分
void getson(int x,int fa){ size[x]=1; for (int i=point[x];i;i=nxt[i]) if (v[i]!=fa) { getson(v[i],x); if (size[v[i]]>size[son[x]]) son[x]=v[i]; size[x]+=size[v[i]]; }}void add(int x,int fa,int vv){ cnt[a[x]]+=vv; if (cnt[a[x]]>maxx) sum=(LL)a[x],maxx=cnt[a[x]]; else if (cnt[a[x]]==maxx) sum+=(LL)a[x]; for (int i=point[x];i;i=nxt[i]) if (v[i]!=fa && v[i]!=Son) add(v[i],x,vv);}void dfs(int x,int fa,int k){ for (int i=point[x];i;i=nxt[i]) if (v[i]!=fa && v[i]!=son[x]) dfs(v[i],x,0); if (son[x])//不是叶子 dfs(son[x],x,1),Son=son[x]; add(x,fa,1);Son=0; ans[x]=sum; if (!k) add(x,fa,-1),maxx=sum=0;//轻儿子 }
在这种做法中,我们先进行树链剖分。
dfs的时候,首先dfs节点x的轻儿子,暴力消去影响,再dfs节点x的下一个轻儿子,一次类推。
然后dfs节点x的重儿子,无需消去影响。
在最后,我们为了统计x,再将x轻儿子的贡献加回来。
看起来很暴力,但是实际上它的时间复杂度是O(nlogn)的,跑得飞快。
证明:只有dfs到轻边时,才会将轻边的子树中合并到上一级的重链,树链剖分将一棵树分割成了不超过logn条重链。
每一个节点最多向上合并logn次,单次修改复杂度O(1)。
所以整体复杂度是O(nlogn)的。
dfs序莫队
一个子树中的节点在dfs序中是连续的,所以可以通过dfs序,将子树问题转化为序列问题,这样就可以跑莫队了。
时间复杂度O(q√n)
dfs序主席树
还可以通过dfs序建出主席树,查询就是差分后的单点查询。
时间复杂度O((n+q)logn) 但是空间复杂度是O(nlogn)的
- [codeforces600E]Lomsat gelral(dsu on the tree+讲解)
- [Codeforces600E]Lomsat gelral(dsu on the tree)
- codeforces600E. Lomsat gelral(dsu on tree)
- 【dsu on tree】Codeforces600E[Lomsat gelral]题解
- codeforces 600 E. Lomsat gelral (dsu on the tree)
- Codeforces 600E Lomsat gelral (DSU on Tree)
- [dsu on tree] Codeforces #600E. Lomsat gelral
- codeforces 600E. Lomsat gelral [dsu on tree(树上启发式合并)]
- codeforces600E Lomsat gelral -- 树上启发式合并
- codeforces 570 D. Tree Requests (dsu on the tree)
- [Codeforces570D]Tree Requests(dsu on the tree)
- [Codeforces375D]Tree and Queries(dsu on the tree+bit)
- [codeforces570D]Tree Requests(dsu on the tree)
- [codeforces375D]Tree and Queries(dsu on the tree+bit)
- codeforces 208 E. Blood Cousins (dsu on the tree)
- [Codeforces208E]Blood Cousins(dsu on the tree+倍增)
- [Codeforces246E]Blood Cousins Return(dsu on the tree+set)
- [codeforces208E]Blood Cousins(dsu on the tree+倍增)
- 搜集卡片 状态压缩+数学期望
- SWERC2016 Performance Review
- poj3468 A Simple Problem with Integers
- UVA10018 字符串处理水题
- jsTL和EL
- [codeforces600E]Lomsat gelral(dsu on the tree+讲解)
- jzoj5400. 【NOIP2017提高A组模拟10.7】Repulsed
- BZOJ 1044: [HAOI2008]木棍分割(二分答案+DP)
- [DP] ZROI 2017提高 5 T2. 石头剪刀布
- 第五章
- 【数据结构】递归
- Unix——系统调用和库函数调用概念区别和联系
- 自定义View实现随机数
- hdoj 6216 A Cubic number and A Cubic Number