标签:编号 first index include tor bsp fir closed note
题意:
有一个树,有些节点染色,每次有两种操作,第一,统计该节点到离它最近的染色父亲结点的的号码(Q),第二,为某一个节点染色(M),求第一种操作和。
输入:
输入由多个数据集组成。每个数据集都有以下格式:
输入的第一行包含两个整数N和Q,分别表示树T中的节点数和操作数。这些数字满足以下条件:1≤N≤100000和1≤Q≤100000。
下面的N-1行,每行包含一个整数pi(i = 2,...,N),它表示第i个节点的父节点的编号。
接下来的Q行按顺序包含操作。每个操作都格式化为“M v”或“Q v”,其中v是节点的编号。
样例:
6 3
1
1
2
3 3
Q 5
M 3
Q 5
0 0
样例输出:
4
分析:
这道题乍一看是一道在树上玩的图论/数据结构题?
但是我想半天都没想到有什么好一点的办法去做这道题。
根据作业专题:并查集,我们来思考如何靠近并查集。
显然并查集的功能是“并”,而这个题的要求显然是“拆”。
我们如果倒过来看,拆就变成并了,而很多拆的题目就是反过来处理使用并查集的。
那我们就把所有询问记录下来,并记录每个点被标记的最早时间。
那我们在查询父节点的时候,条件便是 当前点被标记的时间早于查询时间 ? 该点 :递归父节点(路径压缩)
我们是否担心路径压缩会出错?
不会,因为我们倒序后,压缩的是已经晚于查询节点的时间的,而我们的查询时间是不断向前走的。
代码:
1 #include<set> 2 #include<map> 3 #include<queue> 4 #include<stack> 5 #include<cmath> 6 #include<cstdio> 7 #include<cstring> 8 #include<iostream> 9 #include<algorithm> 10 #define RG register ll 11 #define rep(i,a,b) for(RG i=a;i<=b;++i) 12 #define per(i,a,b) for(RG i=a;i>=b;--i) 13 #define ll long long 14 #define inf (1<<29) 15 #define maxn 100005 16 using namespace std; 17 ll n,T,x,cnt,tim,ans; 18 ll fa[maxn],tag[maxn],qa[maxn],qb[maxn]; 19 inline ll read() 20 { 21 ll x=0,f=1;char c=getchar(); 22 while(c<‘0‘||c>‘9‘){if(c==‘-‘)f=-1;c=getchar();} 23 while(c>=‘0‘&&c<=‘9‘){x=x*10+c-‘0‘;c=getchar();} 24 return x*f; 25 } 26 27 ll find(ll x) 28 { 29 return tag[x]<tim?x:fa[x]=find(fa[x]); 30 } 31 32 int main() 33 { 34 while(1) 35 { 36 n=read(),T=read(); 37 if(n==0&&T==0) return 0; 38 ans=cnt=0; 39 rep(i,2,n) fa[i]=read(),tag[i]=i+T; 40 char s[5]; 41 rep(i,1,T) 42 { 43 scanf("%s",s);x=read(); 44 if(s[0]==‘M‘) 45 tag[x]=min(tag[x],i); 46 else 47 qa[++cnt]=x,qb[cnt]=i; 48 } 49 per(i,cnt,1) 50 { 51 tim=qb[i]; 52 ans+=find(qa[i]); 53 } 54 cout<<ans<<endl; 55 } 56 return 0; 57 }
Marked Ancestor [AOJ2170] [并查集]
标签:编号 first index include tor bsp fir closed note
原文地址:https://www.cnblogs.com/ibilllee/p/9226440.html