Description
在2016年,佳媛姐姐刚刚学习了树,非常开心。
现在他想解决这样一个问题:
给定一颗有根树(根为1),有以下两种操作:
1. 标记操作:对某个结点打上标记(在最开始,只有结点1有标记,其他结点均无标记,而且对于某个结点,可以打多次标记。)
2. 询问操作:询问某个结点最近的一个打了标记的祖先(这个结点本身也算自己的祖
先)你能帮帮他吗?
Solution
这题至少有两种解法。
- 解法1:可以离线处理。把每个操作读入后倒序,就变成了删除节点,也就是合并联通块。这样完全可以用并查集完成。
- 解法2:如果一定要在线的话。可以用树链剖分,每个询问就是要求
1
~
x 的路径上最深的有标记的点。显然这里DFS序越大深度越大。修改就是把这个点改成它的DFS序,线段树维护最大值即可。
解法1的复杂度是
O(N+qα(N))
,码量个人认为1K左右
解法2的复杂度是
O(Nlog2N)
,码量2.7K~~
然而比赛的时候,本人对自己的代码能力十分自信,机(sha)智(bi)的打了解法2。
结果一直拍到11:00
Code
下面是比赛时候打的链剖~
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<iostream>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fod(i,a,b) for(i=a;i>=b;i--)
#define MAXN 100005
using namespace std;
struct note
{
int mx,ls,rs;
}tree[2000005];
struct rd
{
int x,y;
}a[MAXN];
int top[MAXN],size[MAXN],son[MAXN],dfn[MAXN],pt[MAXN],ft[MAXN],deep[MAXN],n,m,a1[MAXN][2],df,num;
bool cmp(rd x,rd y)
{
return x.x<y.x;
}
void dfs1(int k)
{
int i,mx=0;
if (a1[k][0]!=0)
fo(i,a1[k][0],a1[k][1])
{
dfs1(a[i].y);
size[k]+=size[a[i].y];
if (size[a[i].y]>mx)
{
son[k]=a[i].y;
mx=size[a[i].y];
}
}
size[k]++;
}
void dfs2(int k)
{
int i;
dfn[k]=++df;
pt[df]=k;
if (son[k]!=0)
{
top[son[k]]=top[k];
dfs2(son[k]);
}
if (a1[k][0]!=0)
fo(i,a1[k][0],a1[k][1])
{
if(a[i].y==son[k]) continue;
top[a[i].y]=a[i].y;
dfs2(a[i].y);
}
}
int find(int now,int l,int r,int x,int y)
{
if (now==0) return 0;
int ls=tree[now].ls,rs=tree[now].rs;
if (l==x&&r==y) return tree[now].mx;
int mid=(l+r)/2;
if (y<=mid) return find(ls,l,mid,x,y);
else if(x>mid) return find(rs,mid+1,r,x,y);
else return max(find(ls,l,mid,x,mid),find(rs,mid+1,r,mid+1,y));
}
void change(int now,int l,int r,int x,int y,int v)
{
int ls=tree[now].ls,rs=tree[now].rs;
if (l==x&&r==y)
{
tree[now].mx=v;
return;
}
int mid=(l+r)/2;
if (ls==0) ls=tree[now].ls=++num,tree[ls].mx=0;
if (rs==0) rs=tree[now].rs=++num,tree[rs].mx=0;
if (y<=mid) change(ls,l,mid,x,y,v);
else if(x>=mid) change(rs,mid+1,r,x,y,v);
else change(ls,l,mid,x,mid,v),change(rs,mid+1,r,mid+1,y,v);
tree[now].mx=max(tree[ls].mx,tree[rs].mx);
}
int ask(int x,int y)
{
int fx=top[x],fy=top[y];
if (fx==fy)
{
if (deep[x]>deep[y]) swap(x,y);
return find(1,1,n,dfn[x],dfn[y]);
}
else
{
if (deep[fx]<deep[fy]) swap(fx,fy),swap(x,y);
return max(find(1,1,n,dfn[fx],dfn[x]),ask(ft[fx],y));
}
}
int main()
{
cin>>n>>m;
int i,j,k;
deep[1]=1;
memset(size,0,sizeof(size));
df=0;
fo(i,1,n-1)
{
int x,y;
scanf("%d%d",&x,&y);
ft[y]=x;
deep[y]=deep[x]+1;
a[i].x=x;
a[i].y=y;
}
sort(a+1,a+n,cmp);
fo(i,1,n-1)
{
if (a[i].x!=a[i-1].x)
{
a1[a[i].x][0]=i;
a1[a[i-1].x][1]=i-1;
}
}
a1[a[n-1].x][1]=n-1;
top[1]=1;
dfs1(1);
dfs2(1);
num=1;
change(1,1,n,1,1,1);
int pq=0;
fo(i,1,m)
{
char ch;
scanf("\n");
scanf("%c%d",&ch,&k);
if (ch=='Q') printf("%d\n",pt[ask(1,k)]);
else change(1,1,n,dfn[k],dfn[k],dfn[k]);
}
}