【SHTSC2014】三叉神经树

Description

计算神经学作为新兴的交叉学科近些年来一直是学术界的热点。一种叫做SHOI 的神经组织因为其和近日发现的化合物 SHTSC 的密切联系引起了人们的极大关注。
SHOI 组织由若干个 SHOI 细胞构成,SHOI 细胞之间形成严密的树形结构。
每个 SHOI 细胞都有且只有一个输出端,被称为轴突,除了一个特殊的、被称为根细胞的 SHOI 细胞的输出作为整个组织的输出以外,其余细胞的轴突均连向其上级 SHOI 细胞;并且有且只有三个接收端,被称为树突,从其下级细胞或者其它神经组织那里接收信息。SHOI 细胞的信号机制较为简单,仅有 0 和 1 两种。每个 SHOI 细胞根据三个输入端中 0 和 1 信号的多寡输出较多的那一种。
现在给出了一段 SHOI 组织的信息,以及外部神经组织的输入变化情况。请你模拟 SHOI 组织的输出结果。

Input

第一行一个整数:n。表示 SHOI 组织的总细胞个数。SHOI 细胞由 1~n 编号,编号为 1 的是根细胞。
从第二行开始的 n 行,每行三个整数 x1, x2, x3,分别表示编号为 1~n 的 SHOI 细胞的树突连接。1

Output

输出 q 行每行一个整数,对应第 i 次外界输入变化后的根细胞的输出。

Sample Input

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

Sample Output

1
0
0
1
1

HINT

对于 100%的数据,n≤500000,q≤500000。

Solution

一道很巧妙的树剖题目
维护(0,0,1)和(0,1,1)的一段连续的链
如果被修改就对这段链进行区间修改
查询就单点查询就好了
jzoj的栈特别小 特别恶心 所以要打个bfs版本的树剖
有个地方忘记赋值为0了
调了好久
代码量很大 倦生

Code

#include <cstdio>
#include <cstring>
#include <algorithm>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
#define L rt<<1
#define R (rt<<1)|1
using namespace std;
const int N=500005,ncov=-1;
int n,i,j,qq,dfn[N],seq[N],s[N],top[N],fa[N*3],v[N*3];
int a[N][4],q[N];
int read(){
    int sum=0;
    char c=getchar();
    while (c<'0'||c>'9') c=getchar();
    while (c>='0'&&c<='9'){
        sum=sum*10+c-'0';
        c=getchar();}
    return sum;
}
void bfs(){
    int l,r,x,i,res,j;
    l=0,r=1,q[1]=1;
    while (l<r){
        x=q[++l];
        fo(i,1,3) {
            j=a[x][i];
            if (j>n) continue;
            q[++r]=j;}
    }
    fo(i,1,n) s[i]=1,top[i]=i;
    dfn[1]=1,res=1;
    fd(i,n,1) {
        s[fa[q[i]]]+=s[q[i]];
        if (v[q[i]]>=2) v[fa[q[i]]]++;}
    s[0]=0;
    fo(i,1,n){
        x=q[i]; res=dfn[x]; int tmp=0;
        fo(j,1,3) if (a[x][j]<=n&&s[a[x][j]]>s[tmp]) tmp=a[x][j];
        if (tmp) top[tmp]=top[x],dfn[tmp]=res+1,res+=s[tmp];
        fo(j,1,3)
          if (a[x][j]<=n&&a[x][j]!=tmp) dfn[a[x][j]]=res+1,res+=s[a[x][j]];  
    }
    fo(i,1,n) seq[dfn[i]]=i;
}
struct Tseg{
    struct edge{
        int c,s,mx[2];
        void cov(int cc){
            mx[0]=mx[1]=0;
            c=cc; 
            if (c==1) mx[0]=s; if (c==2) mx[1]=s;
        }
    } tr[N<<3];
   void update(edge &rt,edge l,edge r){
     rt.s=l.s+r.s; 
     rt.mx[0]=r.mx[0],rt.mx[1]=r.mx[1];
     if (r.mx[0]==r.s) rt.mx[0]+=l.mx[0];
     if (r.mx[1]==r.s) rt.mx[1]+=l.mx[1]; 
   }
   void pushdown(int rt){
     if (tr[rt].c==ncov) return;
     tr[L].cov(tr[rt].c);
     tr[R].cov(tr[rt].c);
     tr[rt].c=ncov;
   }
   void build(int rt,int l,int r){
      tr[rt].c=ncov;
      if (l==r){
        tr[rt].s=1;
        tr[rt].cov(v[seq[l]]);
        return;}
        int mid=(l+r)>>1;
        build(L,l,mid),build(R,mid+1,r);
        update(tr[rt],tr[L],tr[R]);
   }
   void clear(){ build(1,1,n);}
   edge query(int rt,int l,int r,int x,int y){
      if (l==x&&r==y) return tr[rt];
      pushdown(rt);
      int mid=(l+r)>>1;
      if (y<=mid) return query(L,l,mid,x,y);
        else if (x>mid) return query(R,mid+1,r,x,y);
      edge res;
      update(res,query(L,l,mid,x,mid),query(R,mid+1,r,mid+1,y));
      return res;
   }
   int search(int rt,int l,int r,int x){
      if (l==r) return tr[rt].c;
      pushdown(rt);
      int mid=(l+r)>>1;
      if (x<=mid) return search(L,l,mid,x);
        else return search(R,mid+1,r,x);
   }
   void change(int rt,int l,int r,int x,int y,int c){
      if (l==x&&r==y) {
          tr[rt].cov(c);
          return;}
      pushdown(rt);
      int mid=(l+r)>>1;
      if (y<=mid) change(L,l,mid,x,y,c);
        else if (x>mid) change(R,mid+1,r,x,y,c);
          else change(L,l,mid,x,mid,c),change(R,mid+1,r,mid+1,y,c);
      update(tr[rt],tr[L],tr[R]);
   } 
   void deal(int x,int p,int c){
      for(;top[x]!=top[p];x=fa[top[x]]) change(1,1,n,dfn[top[x]],dfn[x],c);
      change(1,1,n,dfn[p],dfn[x],c);
   }
   int modify(int x){
      int key=v[x];v[x]^=1;
      int tmp=fa[x];
      while (1){
        edge res=query(1,1,n,dfn[top[tmp]],dfn[tmp]);
        if (res.s!=res.mx[key]) break;
        tmp=top[tmp];
        if (!fa[tmp]) break;
        if (search(1,1,n,dfn[fa[tmp]])!=key+1) break;
        tmp=fa[tmp];}
     int p=search(1,1,n,dfn[tmp]);
     if (p!=key+1){
          change(1,1,n,dfn[tmp],dfn[tmp],p+(key?-1:1));
          return search(1,1,n,1)>=2;}
       if (tmp==top[tmp]) p=tmp;
        else p=seq[dfn[tmp]-query(1,1,n,dfn[top[tmp]],dfn[tmp]).mx[key]+1];
       deal(fa[x],p,v[x]+1);
       if (fa[p]) change(1,1,n,dfn[fa[p]],dfn[fa[p]],search(1,1,n,dfn[fa[p]])+(key?-1:1));
       return search(1,1,n,1)>=2;
   }    
} seg;
void work(){
    seg.clear();
    qq=read();
    while (qq){
        qq--;
        i=read();
            printf("%d\n",seg.modify(i));
    }
}
int main(){
    freopen("neuron.in","r",stdin);
    freopen("neuron.out","w",stdout);
    n=read();
    fo(i,1,n)
      fo(j,1,3){
        a[i][j]=read();
        fa[a[i][j]]=i;}
    fo(i,n+1,3*n+1) v[i]=read(),v[fa[i]]+=v[i];
    bfs();
    work();
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值