不知哪个OJ 观察 dfs序

观察

(watch.pas/c/cpp)

限于自己辣鸡的水平,我这道题只有85分(然而考试时只有5分QWQ),想满分的可学习手写栈dfs或bfs求dfs序

【问题描述】

infleaking十分愉快地走在路上,

因为经过10^9^9^9年后,

他得到了一个新技能——观察大法。 

刚出来的infleaking就想要挑战自我。

为什么infleaking会这么自信呢?

因为infleaking做到了可以通过观察数据就就可以得出答案。

但是出题人十分不服,想要将infleaking的气焰打压下去,

于是想到了一道题。

结果被infleaking运用他那强大的观察能力看完数据后给出了答案。

怎么能够让infleaking继续下去呢,出题人于是就将数据重出并且加密了。

没有能直接观察数据的infleaking十分不服气,想要解决这道题,

但是苦于不能直接使用他的新技能,所以想要请聪明的你帮infleaking解决这个问题。

出题人给出一颗以1为根的树,一开始每个节点都是一颗棋子,一面白一面黑,白色的面朝上

接下来就q次操作,操作分两种

0操作 将一个颗棋子翻转

1操作 询问一颗棋子与所有面朝上为黑色的棋子lca最深的那个的编号

【输入】

第1行,两个正整数n,q

第2行,一共n-1个正整数,第i个正整数表示i+1号结点的父亲

第3~q+3每行两个整数x ,第|x|个为被操作的棋子,x>0操作为0否则为1

【输出】

       对于每个op为1的操作输出对应的编号,若场上没有黑棋子输出0

【输入输出样例1】

10 10

6 2 7 9 1 10 5 4 3

-2

1

3

3

-5

8

1

4

-1

-5

0

1

1

5

【数据范围】

 

自己还是太菜。。。考试时把线段树写错。。。QWQ

有一个显然的结论:在dfn序列上,x的前驱或后继之一与x的最近公共祖先是答案(不解释)

然后可以用线段树维护序列,就是单点修改,查前驱后继。

注意85分的原因是会爆栈。。。QWQ

#pragma comment (linker,"/STACK: 1024000000,1024000000")//没有卵用
#include<cstdio>
#include<iostream>
#define ls (tr<<1)
#define rs (tr<<1|1)
#define R register int
const int N=800010;
using namespace std;
inline int g() {
    R ret=0,fix=1; register char ch; while(!isdigit(ch=getchar())) fix=ch=='-'?-1:fix;
    do ret=ret*10+(ch^48); while(isdigit(ch=getchar())); return ret*fix;
}
int n,m,cnt,num,rt,ans;
int vr[N<<1],nxt[N<<1],fir[N],d[N],dfn[N],rw[N],lg[N];
int f[N][21],sum[N<<2];
inline void add(int u,int v) {vr[++cnt]=v,nxt[cnt]=fir[u],fir[u]=cnt;}
inline void dfs(int u) {dfn[u]=++num,rw[num]=u;
    for(R i=fir[u];i;i=nxt[i]) { R v=vr[i];
        if(d[v]) continue; d[v]=d[u]+1,f[v][0]=u; R p=u;
        for(R j=0;f[p][j];++j) f[v][j+1]=f[p][j],p=f[p][j]; dfs(v);
    } 
}
inline int lca(int u,int v) {
    if(d[v]>d[u]) swap(u,v); R lim=lg[d[u]]+1;
    for(R j=lim;j>=0;--j) if(d[f[u][j]]>=d[v]) u=f[u][j];
    if(u==v) return u;
    for(R j=lim;j>=0;--j) if(f[u][j]!=f[v][j]) u=f[u][j],v=f[v][j];
    return f[u][0];
}
inline void upd(int tr) {sum[tr]=sum[ls]+sum[rs];}
inline void change(int tr,int l,int r,int pos) {
    if(l==r) {sum[tr]^=1; return ;} R md=l+r>>1;
    if(pos<=md) change(ls,l,md,pos); else change(rs,md+1,r,pos); upd(tr);
}
inline int getpre(int tr,int l,int r,int pos) { if(!sum[tr]) return 0;
    if(l==r) return l; R md=l+r>>1,tmp; if(pos<=md) return getpre(ls,l,md,pos);
    tmp=getpre(rs,md+1,r,pos); if(tmp) return tmp; return getpre(ls,l,md,pos);
}
inline int getnxt(int tr,int l,int r,int pos) { if(!sum[tr]) return 0;
    if(l==r) return l; R md=l+r>>1,tmp; if(pos>md) return getnxt(rs,md+1,r,pos);
    tmp=getnxt(ls,l,md,pos); if(tmp) return tmp; return getnxt(rs,md+1,r,pos);
}
signed main() {  freopen("watch.in","r",stdin); freopen("watch.out","w",stdout);
    n=g(),m=g(); for(R i=2;i<=n;++i) lg[i]=lg[i>>1]+1;
    for(R i=2,x;i<=n;++i) x=g(),add(i,x),add(x,i); d[1]=1; dfs(1);
    for(R i=1,x;i<=m;++i) { x=g(); 
        if(x>0) change(1,1,n,dfn[x]);
        else { x=-x; ans=0; R pre,nxt;
            pre=getpre(1,1,n,dfn[x]);
            nxt=getnxt(1,1,n,dfn[x]+1); 
            if(pre) {R LCA=lca(rw[pre],x); d[LCA]>d[ans]?ans=LCA:0;}
            if(nxt) {R LCA=lca(rw[nxt],x); d[LCA]>d[ans]?ans=LCA:0;}
            printf("%d\n",ans);
        } 
    }
}

2019.05.04

猜你喜欢

转载自www.cnblogs.com/Jackpei/p/10808770.html