『CSU 1322』ZY‘s new company(线段树维护bfs序)

转载声明:http://blog.csdn.net/alpc_neverfarewell/article/details/39160735

题意:
zzy开了一家公司,然后他为公司制定了人事制度:为每个员工都定一个直接的上属(除了zzy自己),这样就把公司表示成了一个树形的人事关系图,树的最顶端就是zzy自己。如果a的直接上属是b则称a是b的一级下属,接下去的依次称为2级、3级……k级下属。

由于如zzy奇葩的想法,他将改变一部分员工的工资,方法依旧是将员工原来的工资异或一个数,得到新的工资。
(这是中文题意,不可能看不懂吧)

个人感想:
这道题目很有意思,就是有一个又有趣的思想,用线段树维护bfs序,然后通过最近公共祖先(LCA),加上二分就可以找到当前 老板 的c级员工的范围.

这道题还给了个重要的思想,就是区间异或和,这我也没接触过,一道题补了好多知识点,维护bfs序这个我是从来没想到过的,确实不会,
这里写图片描述
首先先做一遍bfs
我们就可以知道每个深度的区间范围
知道这个有有什么用?我们可以对深度范围进行二分,找到对应的父节点的c级员工节点范围并用线段树更新

例如 现在我要找2的 1级员工
我们知道 depth[2]+1==3
第3层的范围是 4-8.
那么我们就二分这个区间点,并且往上走c级
我们就要找到一个 parent[x][c]2 最左节点, 和parent[y][c]>2的左的y,然后y-1 就是2的最右节点了, 然后就可以用线段树维护
我觉得有点神奇,…只是我对这个理解不深啊,
其实我就看了一会转载的博客我就懂了…
我出的最大问题不在建树,只是二分,
因为有可能所查询的节点 根本没c级员工,那只是别人的位置有而已
那么我怎么二分出来 并且 判断这个区间(x,y)合法?
我一直习惯用(r-l>1) 进行二分,这样做有点难度就是 可能你2个点刚好相差1,所有两个位置都没检测,那还要特殊处理,那就好麻烦了…
所以啊,还是我修行不够啊…
挺好的一道题目,值得深思.

分析:线段树+二分+最近公共祖先

AC代码:

/* Author:GavinjouElephant
 * Title:
 * Number:
 * main meanning:
 *
 *
 *
 */


#include <iostream>
using namespace std;
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <sstream>
#include <cctype>
#include <vector>
#include <set>
#include <cstdlib>
#include <map>
#include <queue>
//#include<initializer_list>
//#include <windows.h>
//#include <fstream>
//#include <conio.h>
#define MaxN 0x7fffffff
#define MinN -0x7fffffff
#define lson 2*k
#define rson 2*k+1
typedef long long ll;
const int INF=0x3f3f3f3f;
const int maxn=1e5+10;
int Scan()//读入整数外挂.
{
    int res = 0, ch, flag = 0;

    if((ch = getchar()) == '-')             //判断正负
        flag = 1;

    else if(ch >= '0' && ch <= '9')           //得到完整的数
        res = ch - '0';
    while((ch = getchar()) >= '0' && ch <= '9' )
        res = res * 10 + ch - '0';
    return flag ? -res : res;
}
void Out(int a)    //输出外挂
{
    if(a>9)
        Out(a/10);
    putchar(a%10+'0');
}

int n,q;
class Node
{
public:
    int l;
    int r;
    int lazy;
    int c[30];
};
Node node[4*maxn];

int val[maxn];
int ancestor[30][maxn];
int start[maxn];
int end1[maxn];
int entry[maxn];
int rentry[maxn];
int depth[maxn];

vector<int>G[maxn];
int getAncestor(int a,int dist)
{
    for(int i=20; i>=0; i--)
    {
        if(dist & (1<<i))
        {
            a=ancestor[i][a];
        }
    }
    return a;
}


void pushup(int k)
{
    for (int i = 0; i < 30; i++)
    {
        node[k].c[i] = node[lson].c[i] + node[rson].c[i];
    }
}
void pushdown(int k)
{
    if(node[k].lazy)
    {
        for(int i=0; i<30; i++)
        {
            if(node[k].lazy & (1<<i) )
            {
                node[lson].c[i]=(node[lson].r-node[lson].l+1)-node[lson].c[i];
                node[rson].c[i]=(node[rson].r-node[rson].l+1)-node[rson].c[i];
            }
        }
        node[lson].lazy^=node[k].lazy;
        node[rson].lazy^=node[k].lazy;
    }
    node[k].lazy=0;
}
void build(int l,int r,int k)
{
    node[k].l=l;
    node[k].r=r;
    node[k].lazy=0;
    if(l==r)
    {
        for(int i=0; i<30; i++)
        {
            node[k].c[i]=((val[rentry[l]]>>i)&1);
        }
        return ;
    }
    int mid=(l+r)/2;
    build(l,mid,lson);
    build(mid+1,r,rson);
    pushup(k);
}
void chang(int l,int r,int k,int v)
{
    if(l<=node[k].l&&node[k].r<=r)
    {
        for(int i=0; i<30; i++)
        {
            if(v&(1<<i))
            {
                node[k].c[i]=(node[k].r-node[k].l+1)-node[k].c[i];
            }
        }
        node[k].lazy^=v;
        return ;
    }
    pushdown(k);
    int mid=(node[k].l+node[k].r)/2;
    if(l<=mid) chang(l,min(mid,r),lson,v);
    if(r>mid)  chang(max(mid+1,l),r,rson,v);
    pushup(k);
}
ll getAns(int l,int r,int k)
{
    ll ans=0;
    if(l<=node[k].l&&node[k].r<=r)
    {
        for(int i=0; i<30; i++)
        {
            ans+=(long long) node[k].c[i]<<i;
        }
        return ans;
    }
    pushdown(k);
    int mid=(node[k].l+node[k].r)/2;
    if(l<=mid) ans+=getAns(l,min(mid,r),lson);
    if(r>mid)  ans+=getAns(max(mid+1,l),r,rson);
    return ans;
}
void bfs()//求bfs序
{
     queue<int> q;

     int DEF=1;//时间戳

     q.push(1);
     depth[1]=1;

     while(!q.empty())
     {
         int s=q.front();
         q.pop();

         start[depth[s]]=min(start[depth[s]],DEF);
         end1[depth[s]]=max( end1[depth[s]],DEF);

         rentry[DEF]=s;
         entry[s]=DEF++;

         for(int j=0;j<(G[s].size());j++)
         {
             int son=G[s][j];
             depth[son]=depth[s]+1;
             q.push(son);
         }
     }
}

void init()
{
    for(int i=0; i<=n; i++) G[i].clear();
    memset(ancestor,-1,sizeof(ancestor));
    memset(start,0x3f,sizeof(start));
    memset(end1,0,sizeof(end1));
    memset(depth,0,sizeof(depth));
    memset(entry,0,sizeof(entry));
}
int main()
{
#ifndef ONLINE_JUDGE
    freopen("coco.txt","r",stdin);
    freopen("lala.txt","w",stdout);
#endif
    while(scanf("%d%d",&n,&q)!=EOF)
    {
        n++;
        init();

        for(int i=2; i<=n; i++)
        {
            scanf("%d%d",&ancestor[0][i],&val[i]);
            ancestor[0][i]++;
            G[ ancestor[0][i] ].push_back(i);
        }

        int li=log2(n)+1;
        for(int k=0; k+1<li; k++)
        {
            for(int v=1; v<=n; v++)
            {
                if(ancestor[k][v]<0) ancestor[k+1][v]=-1;
                else ancestor[k+1][v]=ancestor[k][ancestor[k][v]];
            }
        }
        bfs();

        build(1,n,1);

        for(int i=0; i<q; i++)
        {
            int op,b,c,v;
            scanf("%d%d%d",&op,&b,&c);
            if(op==0)
            {
                scanf("%d",&v);
            }

            b++;
            int d=c+depth[b];

            if (d > n || start[d] == INF)
            {
                if (op == 1)
                {
                    printf("-1\n");
                }
                continue;
            }

            int x, y;
            {
                int l = start[d], r = end1[d];
                int ans = end1[d] + 1;
                while (l <= r)
                {
                    int mid = (l + r) >> 1;
                    if (entry[getAncestor(rentry[mid], c)] >= entry[b])
                    {
                        ans = mid;
                        r = mid - 1;
                    }
                    else
                    {
                        l = mid + 1;
                    }
                }
                x = ans;
            }

            {
                int l = start[d], r = end1[d];
                int ans = end1[d] + 1;
                while (l <= r)
                {
                    int mid = (l + r) >> 1;
                    if (entry[getAncestor(rentry[mid], c)] > entry[b])
                    {
                        ans = mid;
                        r = mid - 1;
                    }
                    else
                    {
                        l = mid + 1;
                    }
                }
                y = ans - 1;
            }

            if (y < x)
            {
                if (op)
                {
                    printf("-1\n");
                }
                continue;
            }

            if (op == 0)
            {
                chang(x,y,1,v);
            }
            else
            {
                printf("%lld\n", getAns(x,y,1));
            }

        }


    }

    return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值