标签:
【题意】
给定一棵树,边的颜色为黑或白,初始时全部为白色。维护两个操作:
1.查询u到根路径上的第一条黑色边的标号。
2.将u到v 路径上的所有边的颜色设为黑色。
Notice:这棵树的根节点为1
【题解】
10^6 的数据范围, 树剖是过不了的。
更好的方法?
首先很容易想到 每条边只有 第一次 被染色的时候是有效的, 故可参考 bzoj 2054: 疯狂的馒头 一题用并查集维护向上 第一个白点。 这样每个点保证只会被染一次, 复杂度 是 O(n * k) 的。
然后呢?
我想到一种做法是 dist[i]表示 在 i 时刻之前, 当前点向上最近一条黑边的深度。按照 dfs 的顺序更新,每访问到一个点, 把大于等于(这个点与它父亲的连边 被染黑的时刻)的时刻 的 dist 都改成 这个点与它父亲的连边的深度, 嗯感觉很靠谱,区间修改开一棵可持久化线段树就好了。
orz Towerlight 告诉我 它的 dist 显然是单调的, 所以 随便用单调栈搞搞就好啦, 我说单调栈怎么可持久化啊, 他说这不用 可持久化 只要可以回溯就可以了啊, 我说那怎么 可回溯化啊 , 他说你就就是弱啊, 连 [Noi2014]购票 都没写过. 后来我想了想好像的确是可以搞的, 写单调栈的时候并不把栈中的元素删掉, 而是开个东西指过去, 再把原来指向的地方 保存下来就行了!!
嗯这种方法应该是可以的。
下面说一下标解的优美做法:
其实像 预处理时的那样用并查集倒着扫过去一遍就够啦! 预处理的时候是把一棵白树染黑, 这时候把一棵黑树染白就可以了。fat2维护当前点 向上第一个黑点, 按照时间倒着扫, 把 first(第一次变黑的时刻)等于当前时间的点 染白, 然后 询问就是 find(x) 了,,就这么简单,,
实现也很容易:
#include <iostream> #include <cstdio> #include <cmath> #include <algorithm> #include <cstring> #define MAXN 1000005 using namespace std; int n, m, head[MAXN], change[MAXN], fat[MAXN], ee, deep[MAXN], numm[MAXN], fat2[MAXN], first[MAXN], la[MAXN], cnt[MAXN]; struct Edge{int to, next, num;}edge[MAXN * 2]; inline void addedge(int x, int y, int id){edge[++ ee].to = y; edge[ee].next = head[x]; head[x] = ee; edge[ee].num = id;} void dfs(int x, int fatt){ fat[x] = fatt; deep[x] = deep[fatt] + 1; for(int i = head[x]; i != -1; i = edge[i].next)if(edge[i].to != fatt) numm[edge[i].to] = edge[i].num, dfs(edge[i].to, x); } inline int get(int x){return x == fat2[x] ? x : fat2[x] = get(fat2[x]);} void color (int x, int y, int tt){ x = get(x), y = get(y); while(x != y){ if(deep[x] < deep[y])swap(x, y); if(first[x] != m + 1)x = fat2[x]; else fat2[x] = fat2[fat[x]], first[x] = tt, x = fat[x]; } } int main() { scanf("%d%d", &n, &m); memset(head, -1, sizeof(head)); memset(la, -1, sizeof(la)); for(int i = 1; i < n; i ++){ int x, y; scanf("%d%d", &x, &y); addedge(x, y, i); addedge(y, x, i); } for(int i = 1; i <= n; i ++)fat2[i] = i, first[i] = m + 1; dfs(1, 1); for(int i = 1; i <= m; i ++){ int x, y; scanf("%d", &x); if(x == 2){ scanf("%d%d", &x, &y); color (x, y, i); }else scanf("%d", &la[i]); } for(int i = 1; i <= n; i ++) ++ cnt[first[i]]; for(int i = 1; i <= m + 1; i ++)cnt[i] += cnt[i - 1]; for(int i = 1; i <= n; i ++)change[cnt[first[i]] --] = i; for(int i = 1; i <= n; i ++)fat2[i] = i; int all = n, u; for(int i = m + 1; i; i --){ if(la[i] != -1)la[i] = numm[get(la[i])]; else for(; all && first[u = change[all]] == i; all --) fat2[u] = fat2[fat[u]]; } for(int i = 1; i <= m; i ++) if(la[i] != -1)printf("%d\n", la[i]); return 0; }
标签:
原文地址:http://www.cnblogs.com/lixintong911/p/4213526.html