[BZOJ][Tjoi2016&Heoi2016]树

题解:这个题有两种做法吧   不嫌麻烦就直接无脑维护子树里面深度深度最大的位置   比较简单几乎可以线性的做法就是  用并查集倒着过来维护联通  每个点所在联通快的根就是答案

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <stack>
#include <queue>
#include <cmath>
#include <set>
#include <map>
#define mp make_pair
#define pb push_back
#define pii pair<int,int>
#define link(x) for(edge *j=h[x];j;j=j->next)
#define inc(i,l,r) for(int i=l;i<=r;i++)
#define dec(i,r,l) for(int i=r;i>=l;i--)
const int MAXN=3e5+10;
const double eps=1e-8;
#define ll long long
using namespace std;
struct edge{int t;edge*next;}e[MAXN<<1],*h[MAXN],*o=e;
void add(int x,int y){o->t=y;o->next=h[x];h[x]=o++;}
ll read(){
    ll x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
    return x*f;
}


typedef struct node{
    int op,x;
}node;
node d[MAXN];

int fa[MAXN];
int f[MAXN];
int vis[MAXN];


int find1(int x){
    if(x==f[x])return x;
    else return f[x]=find1(f[x]);
}


void dfs(int x,int pre){
    fa[x]=pre;
    if(!vis[x])f[x]=find1(f[pre]);
    link(x){
	dfs(j->t,x);
    }
}

stack<int>s;
int main(){
    int n=read(),m=read();
    int u,v;
    inc(i,2,n)u=read(),v=read(),add(u,v);
    char str[11];vis[1]=1;
    inc(i,1,m){
	scanf("%s %d",str,&u);
	if(str[0]=='Q')d[i].op=1,d[i].x=u;
	else d[i].op=2,d[i].x=u,vis[u]++;
    }
    inc(i,1,n)f[i]=i;
    dfs(1,0);
    dec(i,m,1){
	if(d[i].op==1)s.push(find1(d[i].x));
	else {
	    if(vis[d[i].x]){
		vis[d[i].x]--;
		if(!vis[d[i].x])f[d[i].x]=find1(fa[d[i].x]);
	    }
	}
    }
    while(!s.empty()){
	printf("%d\n",s.top());
	s.pop();
    }
}

  

4551: [Tjoi2016&Heoi2016]树

Time Limit: 20 Sec  Memory Limit: 128 MB
Submit: 2109  Solved: 1013
[Submit][Status][Discuss]

Description

在2016年,佳媛姐姐刚刚学习了树,非常开心。现在他想解决这样一个问题:给定一颗有根树(根为1),有以下
两种操作:1. 标记操作:对某个结点打上标记(在最开始,只有结点1有标记,其他结点均无标记,而且对于某个
结点,可以打多次标记。)2. 询问操作:询问某个结点最近的一个打了标记的祖先(这个结点本身也算自己的祖
先)你能帮帮他吗?

Input

输入第一行两个正整数N和Q分别表示节点个数和操作次数接下来N-1行,每行两个正整数u,v(1≤u,v≤n)表示u到v
有一条有向边接下来Q行,形如“opernum”oper为“C”时表示这是一个标记操作,oper为“Q”时表示这是一个询
问操作对于每次询问操作,1 ≤ N, Q ≤ 100000。

Output

输出一个正整数,表示结果

Sample Input

5 5
1 2
1 3
2 4
2 5
Q 2
C 2
Q 2
Q 5
Q 3

Sample Output

1
2
2
1

HINT

 新加数据9组(By HFLSyzx ),未重测--2016.8.2

猜你喜欢

转载自www.cnblogs.com/wang9897/p/10336377.html