题目链接:
http://acm.csu.edu.cn/OnlineJudge/problem.php?id=1811
题目大意:
一棵树,N(2<=N<=105)个节点,每个节点有一种颜色Ci(Ci<=N),问把每一条边删掉后,剩下的两个联通块中颜色的交集的大小(就是两边都含有的颜色种数)。
题目思路:
【树状数组】
我的数据结构造诣不深,这题写了暴力求每个点的颜色数T了。看了别人的题解写了超级久WA了好多才过。
首先可以知道,如果已知每个节点的子树中含有的颜色种数C和只出现在这棵子树的颜色种数D,那么这个节点和它的父亲节点中间的那条边被删去后的答案就是C-D。
所以问题变为求以每个节点为根的子树中的C和D值。然后我想到这里就不知道要怎么写了。看了大神的题解才有一点思路。(不过我感觉大神的题解好像有点问题??)
首先转化成dfs序,按照遍历这棵树的顺序求出每个节点的新的从小到大的标号q[u].b(父亲标号先前于儿子),同时记下原先对应的节点标号q[u].id
预处理出对于颜色ci,记pre[ci]为ci上次出现的颜色位置,L[ci],R[ci]为ci出现的最左最右端。然后按照新的dfs序标号从小到大做
对于节点i,将pre[ci]到i之间的所有点ans+1(因为答案是一条条树链统计的,不会计算到兄弟节点,实际影响的只有这个节点以上的父亲节点,所以答案不会出错,本质上相当于把L[ci]到R[ci]所有的点都ans+1,但是只有有这种颜色的节点到根的树链上的点会加上答案,这样其实是没错的)
如果到了颜色的最右端,把这种颜色最左端左边的答案删掉(因为一开始pre默认是0,会把1~L[ci]中的答案+1,需要扣除,也可以一开始就从L[ci]开始加)
到达叶子结点后统计这条树链的答案。以上的ans可以用树状数组统计。
//
//by coolxxx
//#include
#include
#include
#include
#include
#include