1. 程式人生 > >[BZOJ][Tjoi2016&Heoi2016]樹

[BZOJ][Tjoi2016&Heoi2016]樹

ring 聯通 標記 esp true -- tchar href tac

題解:這個題有兩種做法吧 不嫌麻煩就直接無腦維護子樹裏面深度深度最大的位置 比較簡單幾乎可以線性的做法就是 用並查集倒著過來維護聯通 每個點所在聯通快的根就是答案

#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

[BZOJ][Tjoi2016&Heoi2016]樹