链接
http://www.lydsy.com/JudgeOnline/problem.php?id=4551
题解
还行吧这道题,不是特别傻逼。
一个点被标记,显然会影响到子树中的所有点。
显然每次查询会选择这个点到根的路径上深度最深的那个祖先点作为答案。
做法一
离线并查集,ftm用了这种方法,倒序变成删除标记。剩下的细节请读者思考。
做法二
LCT直接暴力,一开始想用这个,但是看到题目下方:新加了九组测试数据,我就知道它想卡这个。弃疗。
做法三
这个算法我感觉长得比较像正解。
算出dfs序,每次修改,就把这个点的子树对这个点的深度取个max。
线段树区间取max,单点查询。
代码
//线段树
#include <cstdio>
#include <algorithm>
#define maxn 200010
using namespace std;
int tid[maxn], ltid[maxn], rtid[maxn], untid[maxn], N, Q, nex[maxn], to[maxn],
head[maxn], tot, ndtot, deep[maxn];
inline void adde(int a, int b){to[++tot]=b;nex[tot]=head[a];head[a]=tot;}
struct segtree{int l, r, tag, max; segtree *ch[2];}pool[maxn], *root;
inline int read(int x=0)
{
char c=getchar();
while(c<48 or c>57)c=getchar();
while(c>=48 and c<=57)x=(x<<1)+(x<<3)+c-48, c=getchar();
return x;
}
inline char readc()
{
char c=getchar();
while(c!='Q' and c!='C')c=getchar();
return c;
}
void dfs(int pos)
{
int p;
ltid[pos]=tid[pos]=++tid[0];untid[tid[pos]]=pos;
for(p=head[pos];p;p=nex[p])deep[to[p]]=deep[pos]+1, dfs(to[p]);
rtid[pos]=tid[0];
}
void build(segtree *p, int l, int r)
{
int mid=(l+r)>>1;
p->l=l, p->r=r;
if(l==r)return;
build(p->ch[0]=pool+ ++ndtot,l,mid);
build(p->ch[1]=pool+ ++ndtot,mid+1,r);
}
void init()
{
int a, b, i;
N=read(), Q=read();
for(i=1;i<N;i++)a=read(), b=read(), adde(a,b);
deep[1]=1, dfs(1);
build(root=pool+ ++ndtot,1,N);
}
inline void u(int a, int &b){if(deep[a]>deep[b])b=a;}
inline void tag(segtree *p, int tag){u(tag,p->tag);}
inline void pushdown(segtree *p)
{
u(p->tag,p->max);
if(p->ch[0])tag(p->ch[0],p->tag),tag(p->ch[1],p->tag);
}
inline void update(segtree *p)
{
if(!p->ch[0])return;
pushdown(p->ch[0]), pushdown(p->ch[1]);
if(deep[p->ch[0]->max]>deep[p->ch[1]->max])p->max=p->ch[0]->max;
else p->max=p->ch[1]->max;
}
void segchg(segtree *p, int l, int r, int a)
{
pushdown(p);
int mid=(p->l+p->r)>>1;
if(l<=p->l and r>=p->r){tag(p,a);return;}
if(l<=mid)segchg(p->ch[0],l,r,a);
if(r>mid)segchg(p->ch[1],l,r,a);
update(p);
}
int segmax(segtree *p, int l, int r)
{
pushdown(p);
int mid=(p->l+p->r)>>1, ans=0;
if(l<=p->l and r>=p->r)return p->max;
if(l<=mid)u(segmax(p->ch[0],l,r),ans);
if(r>mid)u(segmax(p->ch[1],l,r),ans);
return ans;
}
void work()
{
int pos;
char type;
tag(root,1);
while(Q--)
{
type=readc();
pos=read();
if(type=='C')segchg(root,ltid[pos],rtid[pos],pos);
else printf("%d\n",segmax(root,tid[pos],tid[pos]));
}
}
int main()
{
init();
work();
return 0;
}
本文介绍了一种解决特定树形结构问题的方法,通过离线并查集、LCT和线段树等数据结构来优化查询效率。重点讨论了一个具体的编程挑战案例,详细解析了如何利用线段树进行区间最大值更新和单点查询的操作。
598

被折叠的 条评论
为什么被折叠?



