马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
x
平常很少做dfs序相干的题,算是复习一下吧。
题目大意
给你一棵树,每个节点有好坏两种颜色,初始都是白色,现在支持以下两种操作:
- 将一个节点的颜色翻转
- 询问某个节点与所有黑色节点分别求lca后得到的深度最大的结果
n , q ≤ 8 × 1 0 5 n,q≤8 \times 10^5 n,q≤8×105。
题解
有一个著名但是赛时被我忘了的结论,某个点与一个特定点集合的lca中深度最大的必定是跟这个点dfs序最接近的两个点(前驱和后继)中的一个。
那么就变成蠢题了,对于翻转操作维护一下点集合,询问操作每次只需要找到dfs序的前驱后继并求lca再比力即可。对于维护和查找官方题解用的是线段树,而我选择set。
Code
- #include<bits/stdc++.h>
- using namespace std;
- const int N=8e5+5;
- int n,m,cnt,num,a[N],fa[N],dep[N],siz[N],dfn[N],tid[N],top[N],son[N],head[N];
- bool b[N];
- set<int> s;
- struct edge{
- int to,nxt;
- }e[N];
- void add(int u,int v){
- e[++cnt]=(edge){v,head[u]};
- head[u]=cnt;
- }
- void dfs1(int u,int f,int d){
- siz[u]=1,fa[u]=f,dep[u]=d;
- for(int i=head[u];i;i=e[i].nxt){
- int v=e[i].to;
- dfs1(v,u,d+1);
- siz[u]+=siz[v];
- if(siz[v]>siz[son[u]]) son[u]=v;
- }
- }
- void dfs2(int u,int tp){
- dfn[u]=++num,tid[num]=u,top[u]=tp;
- if(!son[u]) return;
- dfs2(son[u],tp);
- for(int i=head[u];i;i=e[i].nxt){
- int v=e[i].to;
- if(v==son[u]) continue;
- dfs2(v,v);
- }
- }
- int lca(int x,int y){
- while(top[x]!=top[y]){
- if(dep[top[x]]<dep[top[y]]) swap(x,y);
- x=fa[top[x]];
- }
- return dep[x]<dep[y]?x:y;
- }
- int main(){
- freopen("watch.in","r",stdin);
- freopen("watch.out","w",stdout);
- scanf("%d%d",&n,&m);
- for(int i=2,x;i<=n;i++){
- scanf("%d",&x);
- add(x,i);
- }
- dfs1(1,0,0);
- dfs2(1,1);
- for(int i=1,x;i<=m;i++){
- scanf("%d",&x);
- if(x>0){
- b[x]=!b[x];
- if(b[x]) s.insert(dfn[x]);
- else s.erase(dfn[x]);
- }
- else{
- x=-x;
- if(s.size()==0){
- printf("0\n");
- continue;
- }
- set<int>::iterator it=s.lower_bound(dfn[x]);
- int ans1=0,ans2=0;
- if(it!=s.end()) ans1=lca(tid[*it],x);
- if(it!=s.begin()){
- it--;
- ans2=lca(tid[*it],x);
- }
- if(!ans1&&!ans2) printf("0\n");
- else if(!ans1||!ans2) printf("%d\n",ans1+ans2);
- else printf("%d\n",dep[ans1]>dep[ans2]?ans1:ans2);
- }
- }
- return 0;
- }
复制代码 免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |