观察
(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