标签:时间复杂度 开始 [1] div ext nbsp 问题 sample cst
题目描述
输入
输出
输出一个正整数,表示结果
样例输入
5 5
1 2
1 3
2 4
2 5
Q 2
C 2
Q 2
Q 5
Q 3
样例输出
1
2
2
1
题解
在线的话可以树剖,然而我选择了离线处理+并查集。
加标记比较难搞,我们可以换一种思路,先把所有标记加进来,再从后往前删掉。
每个节点的f为最近的有标记的祖先,这可以在dfs中直接实现。
然后从后往前处理,如果是修改则删标记,删为0时直接将该点的f赋为f[fa]。
如果是查询,直接记录find即可。
理论时间复杂度O(αN),然而这么慢也是醉了。
另外听说暴力可过。
#include <cstdio>
#include <algorithm>
#define N 100010
using namespace std;
int head[N] , to[N << 1] , next[N << 1] , cnt , fa[N] , t[N] , f[N] , opt[N] , p[N] , ans[N];
char str[5];
void add(int x , int y)
{
to[++cnt] = y , next[cnt] = head[x] , head[x] = cnt;
}
void dfs(int x , int last)
{
if(t[x]) last = x;
f[x] = last;
int i;
for(i = head[x] ; i ; i = next[i])
if(to[i] != fa[x])
fa[to[i]] = x , dfs(to[i] , last);
}
int find(int x)
{
return x == f[x] ? x : f[x] = find(f[x]);
}
int main()
{
int n , m , i , x , y;
scanf("%d%d" , &n , &m);
for(i = 1 ; i < n ; i ++ ) scanf("%d%d" , &x , &y) , add(x , y) , add(y , x);
t[1] = 1;
for(i = 1 ; i <= m ; i ++ )
{
scanf("%s%d" , str , &p[i]);
if(str[0] == ‘C‘) opt[i] = 1 , t[p[i]] ++ ;
}
dfs(1 , 0);
for(i = m ; i >= 1 ; i -- )
{
if(opt[i])
{
t[p[i]] -- ;
if(!t[p[i]]) f[p[i]] = f[fa[p[i]]];
}
else ans[i] = find(p[i]);
}
for(i = 1 ; i <= m ; i ++ ) if(!opt[i]) printf("%d\n" , ans[i]);
return 0;
}
【bzoj4551】[Tjoi2016&Heoi2016]树 离线处理+并查集
标签:时间复杂度 开始 [1] div ext nbsp 问题 sample cst
原文地址:http://www.cnblogs.com/GXZlegend/p/6670292.html