4551: [Tjoi2016&Heoi2016]树

4551: [Tjoi2016&Heoi2016]树

Time Limit: 20 Sec   Memory Limit: 128 MB
Submit: 503   Solved: 304
[ 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

Source

[ Submit][ Status][ Discuss]

用dfs序把所有点排成一排,就可以区间赋值啦
#include<iostream>
#include<cstdio>
#include<queue>
#include<vector>
#include<bitset>
#include<algorithm>
#include<cstring>
#include<map>
#include<stack>
#include<set>
#include<cmath>
#include<ext/pb_ds/priority_queue.hpp>
using namespace std;

const int maxn = 1E5 + 10;

int n,m,dfs_clock,Root,dfn[maxn],L[maxn],out[maxn],a[maxn*20],c[maxn*20];
bool Mark[maxn];
char com[10];

vector <int> v[maxn];

void dfs(int x,int from)
{
	dfn[x] = ++dfs_clock;
	for (int i = 0; i < v[x].size(); i++) {
		int to = v[x][i];
		if (to == from) continue;
		L[to] = L[x] + 1;
		dfs(to,x);
	}
	out[x] = dfs_clock;
}

void pushdown(int o)
{
	if (a[o]) {
		int lc = 2*o,rc = 2*o+1;
		if (!c[lc] || L[c[lc]] < L[a[o]]) c[lc] = a[o];
		if (!a[lc] || L[a[lc]] < L[a[o]]) a[lc] = a[o];
		if (!c[rc] || L[c[rc]] < L[a[o]]) c[rc] = a[o];
		if (!a[rc] || L[a[rc]] < L[a[o]]) a[rc] = a[o];
		a[o] = 0;
	}
}

void Modify(int o,int l,int r,int ml,int mr,int modi)
{
	pushdown(o);
	if (ml <= l && r <= mr) {
		if (c[o] && L[c[o]] > L[modi]) return;
		c[o] = a[o] = modi; return;
	}
	int mid = (l + r) >> 1;
	if (ml <= mid) Modify(2*o,l,mid,ml,mr,modi);
	if (mr > mid) Modify(2*o+1,mid+1,r,ml,mr,modi);
}

int Query(int o,int l,int r,int pos)
{
	if (l == r) return c[o];
	pushdown(o);
	int mid = (l + r) >> 1;
	if (pos <= mid) return Query(2*o,l,mid,pos);
	else return Query(2*o+1,mid+1,r,pos);
}

int main()
{
	#ifdef DMC
		freopen("DMC.txt","r",stdin);
	#endif
	
	cin >> n >> m;
	for (int i = 1; i < n; i++) {
		int x,y; scanf("%d%d",&x,&y);
		v[x].push_back(y);
		v[y].push_back(x);
	}
	Root = 1; L[Root] = 1; dfs(Root,0);
	Mark[1] = 1; Modify(1,1,n,1,n,1);
	while (m--) {
		scanf("%s",com);
		int x; scanf("%d",&x);
		if (com[0] == 'C') {
			if (Mark[x]) continue;
			Modify(1,1,n,dfn[x],out[x],x);
			Mark[x] = 1;
		}
		else printf("%d\n",Query(1,1,n,dfn[x]));
	}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值