[jzoj5786]【NOIP2008模拟】观察 (dfs序+lca)

[jzoj5786]【NOIP2008模拟】观察 (dfs序+lca)

传送门

Description

infleaking十分愉快地走在路上,
因为经过10^9^9^9年后,
他得到了一个新技能——观察大法。

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

为什么infleaking会这么自信呢?

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

但是出题人十分不服,想要将infleaking的气焰打压下去,
于是想到了一道题。

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

怎么能够让infleaking继续下去呢,出题人于是就将数据重出并且加密了。
没有能直接观察数据的infleaking十分不服气,想要解决这道题,
但是苦于不能直接使用他的新技能,所以想要请聪明的你帮infleaking解决这个问题。

出题人给出一颗以1为根的树,一开始每个节点都是一颗棋子,一面白一面黑,白色的面朝上
接下来就q次操作,操作分两种
0操作 将一个颗棋子翻转
1操作 询问一颗棋子与所有面朝上为黑色的棋子lca最深的那个的编号

Input

第1行,两个正整数n,q
第2行,一共n-1个正整数,第i个正整数表示i+1号结点的父亲
第3~q+3每行两个整数x ,第|x|个为被操作的棋子,x>0操作为0否则为1

Output

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

Sample Input

10 10
6 2 7 9 1 10 5 4 3
-2
1
3
3
-5
8
1
4
-1
-5

Sample Output

0
1
1
5

Data Constraint

+uxDAPAFqJ9hrAkC8Cm2SQuJC4DPRBIEAAA66f8DL8GhT5f03+QAAAAASUVORK5CYII=

Solution

查询时找dfn序比它小和dfn序比它大的第一个黑点的lca即可
直接dfs会溢栈,不会手写栈,bfs水过qwq

Code

//By Menteur_Hxy
#pragma GCC diagnostic error "-std=c++11"
#pragma GCC optimize("-fdelete-null-pointer-checks,inline-functions-called-once,-funsafe-loop-optimizations,-fexpensive-optimizations,-foptimize-sibling-calls,-ftree-switch-conversion,-finline-small-functions,inline-small-functions,-frerun-cse-after-loop,-fhoist-adjacent-loads,-findirect-inlining,-freorder-functions,no-stack-protector,-fpartial-inlining,-fsched-interblock,-fcse-follow-jumps,-fcse-skip-blocks,-falign-functions,-fstrict-overflow,-fstrict-aliasing,-fschedule-insns2,-ftree-tail-merge,inline-functions,-fschedule-insns,-freorder-blocks,-fwhole-program,-funroll-loops,-fthread-jumps,-fcrossjumping,-fcaller-saves,-fdevirtualize,-falign-labels,-falign-loops,-falign-jumps,unroll-loops,-fsched-spec,-ffast-math,Ofast,inline,-fgcse,-fgcse-lm,-fipa-sra,-ftree-pre,-ftree-vrp,-fpeephole2",3)
#pragma GCC target("avx","sse2")
//以上自动忽略qwq
#include<set>
#include<cstdio>
#include<vector>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define int long long
#define F(i,a,b) for(register int i=(a);i<=(b);i++)
#define R(i,a,b) for(register int i=(b);i>=(a);i--)
#define E(i,u) for(register int i=head[u];i;i=nxt[i])
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin)),p1==p2?EOF:*p1++)
using namespace std;
typedef long long LL;

char buf[1<<21],*p1,*p2;
inline int read() {
    int x=0,f=1; char c=getchar();
    while(!isdigit(c)) {if(c=='-')f=-f;c=getchar();}
    while(isdigit(c)) x=(x<<1)+(x<<3)+c-48,c=getchar();
    return x*f;
}

const int N=800010;
int n,q,tot,cnt;
int dfn[N],id[N],f[N][24],dep[N],nxt[N],to[N],head[N],siz[N],que[N];
set <int> S;
set <int>::iterator it;

int lca(int x,int y) {
    if(dep[x]<dep[y]) swap(x,y);
    int need=dep[x]-dep[y];
    for(int i=0;need;need>>=1,i++) if(need&1) x=f[x][i];
    if(x!=y) {
        R(i,0,21) if(f[x][i]!=f[y][i]) 
            x=f[x][i],y=f[y][i];
        return f[x][0];
    }
    return x;
}

void dfs(int u) {
    siz[u]=1;
    dfn[u]=++tot; id[dfn[u]]=u;
    E(i,u) {
        int v=to[i];
        dep[v]=dep[u]+1;
        f[v][0]=u;
        dfs(v);
        siz[u]+=siz[v];
    }
}

void bfs1() {
    int h=0,t=1;
    que[++h]=1;
    while(h<=t) {
        int u=que[h++];
        siz[u]=1;
        E(i,u) {
            int v=to[i];
            dep[v]=dep[u]+1,f[v][0]=u;
            que[++t]=v;
        }
    }
    R(i,1,n) siz[f[que[i]][0]]+=siz[que[i]];
}

void bfs2() {
    int h=0,t=1;
    que[++h]=1;dfn[1]=1; id[dfn[1]]=1;
    while(h<=t) {
        int u=que[h++],last=u;
        E(i,u) {
            int v=to[i];
            dfn[v]=dfn[last]+(last!=u?siz[last]:1);
            id[dfn[v]]=v;
            que[++t]=v;
            last=v;
        }
    }
}

#define add(a,b) nxt[++cnt]=head[a],to[cnt]=b,head[a]=cnt
signed main() {
    freopen("watch.in","r",stdin);
    freopen("watch.out","w",stdout);
    n=read(),q=read();
    F(i,1,n-1) {int u=read();add(u,i+1);}
//  dfs(1); 通往溢栈的钥匙233
    bfs1(),bfs2();
//  F(i,1,n) printf("%d ",dep[i]);putchar('\n');
    for(register int j=1;(1<<j)<=n;j++) 
        F(i,1,n) if(f[i][j-1]) 
            f[i][j]=f[f[i][j-1]][j-1];
    dep[0]=-1;
    F(i,1,q) {
        int x=read(),fla=0;
        if(x<0) fla=1,x=-x;
        if(!fla) {
            if(!S.insert(dfn[x]).second) S.erase(dfn[x]);
            continue;
        }
        if(S.empty()) {
            putchar('0');
            putchar('\n');
            continue;
        }
        int t1=0,t2=0;
        it=S.lower_bound(dfn[x]);
        if(it!=S.end()) t1=lca(x,id[*it]);
        if(it!=S.begin()) it--,t2=lca(x,id[*it]);
//      __builtin_printf("%d %d\n",t1,t2);
        if(dep[t1]<dep[t2]) printf("%d\n",t2);
        else printf("%d\n",t1);
    }
    return 0;
}
posted @ 2018-08-10 18:50 Menteur_Hxy 阅读( ...) 评论( ...) 编辑 收藏
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值