睡觉困难综合症(树链剖分+线段树)

睡觉困难综合症

题目描述

由乃这个问题越想越迷糊,已经达到了废寝忘食的地步。结果她发现……晚上睡不着了!只能把自己的一个神经元(我们可以抽象成一个树形结构)拿出来,交给Deus。

这个神经元是一个有 n n 个点的树,每个点的包括一个位运算opt和一个权值 x x ,位运算有&,l,^三种,分别用1,2,3表示。

为了治疗失眠,Deus可以将一些神经递质放在点x上,初始的刺激值是 v0 v 0

然后 v v 依次经过从x y y 的所有节点,每经过一个点i v v 就变成v opti o p t i xi x i ,所以他想问你,最后到 y y 时,希望得到的刺激值尽可能大,所以最大值的v可以是多少呢?当然由于初始的神经递质的量有限,所以给定的初始值 v0 v 0 必须是在 [0,z] [ 0 , z ] 之间。Deus每次都会给你3个数, x x ,y, z z

不过,Deus为了提升治疗效果,可能会对一些神经节点进行微调。在这种情况下,也会给三个数x y y z,意思是把 x x 点的操作修改为y,数值改为 z z

输入格式:

第一行三个数n m m k k k 的意义是每个点上的数,以及询问中的数值z都 < 2k 2 k

之后 n n 行,每行两个数x, y y 表示该点的位运算编号以及数值

之后n - 1行,每行两个数 x x ,y表示 x x y之间有边相连

之后 m m 行,每行四个数,Q, x x ,y, z z 表示这次操作为Q(1位询问,2为更改), x x y z z 意义如题所述

输出格式:

对于每个操作1,输出到最后可以造成的最大刺激度v
   
   
   
   
   
   
看不懂可以传送到洛谷去。
   
   
   
   
   
   
   
   

解:

如题,这个是NOI某年T1的加强版。如果没有做过起床困难综合症,建议先去做一下那道,虽然蒟蒻的我并没有做~
最近刷树剖板子似乎稍微熟练了那么一点。
似乎可以用LCT,时间复杂度更优秀,但是我不会啊!!!!!
那我们就树剖吧(惊人码量)。
为什么要来做这道题?最近听到高二的学长讲线段树维护位运算的姿势,想来练一练,正好选到这道题了。
还是使用原来题目的思想,用全1跑一遍全0跑一遍,看看对应位置会变成什么,然后贪心。
如何维护链上信息,同样树剖,使用线段树维护经过一段区间操作全1会变成什么全0会变成什么。
由于不知道树链的方向,我们还要维护从上到下和从下到上。也就是说,线段树上要维护4个值。

写的时候,线段树没开够,左移没打1LL,维护从上到下和从下到上搞反了。这个故事告诉我们不要在午休之前写代码。

还是贴波代码吧(树剖现在日常6KB了,是不是我姿势不够高超?):

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<stack>
using namespace std;
struct lxy{
    int to,next;
}eg[200005];
struct segment_tree{
    int lson,rson,l,r;
    unsigned long long upone,upzero,done,dzero;
}b[200005];
struct barg{
    unsigned long long zero,one;
}hhh;
int fa[100005],tp[100005],size[100005],wson[100005];
int opt[100005],bl[100005],dep[100005],head[100005];
bool vis[100005];
unsigned long long v[100005],inf;
int n,m,k,cnt,root;

void build(int &u,int l,int r)
{
    u=++cnt;
    b[u].l=l,b[u].r=r;
    if(l==r) return;
    int mid=(l+r)>>1;
    build(b[u].lson,l,mid);
    build(b[u].rson,mid+1,r);
}

void update(int u)
{
    b[u].dzero=((b[b[u].lson].dzero&b[b[u].rson].done)|((~b[b[u].lson].dzero)&b[b[u].rson].dzero));
    b[u].done=((b[b[u].lson].done&b[b[u].rson].done)|((~b[b[u].lson].done)&b[b[u].rson].dzero));
    b[u].upzero=((b[b[u].rson].upzero&b[b[u].lson].upone)|((~b[b[u].rson].upzero)&b[b[u].lson].upzero));
    b[u].upone=((b[b[u].rson].upone&b[b[u].lson].upone)|((~b[b[u].rson].upone)&b[b[u].lson].upzero));
    return;
}

void modify(int u,int pos,int opti,unsigned long long vi)
{
    if(b[u].l==b[u].r)
    {
        if(opti==1)
        {
            b[u].upone=vi,b[u].upzero=0;
            b[u].done=vi,b[u].dzero=0;
        }
        if(opti==2)
        {
            b[u].upone=inf,b[u].upzero=vi;
            b[u].done=inf,b[u].dzero=vi;
        }
        if(opti==3)
        {
            b[u].upone=(inf^vi),b[u].upzero=vi;
            b[u].done=(inf^vi),b[u].dzero=vi;
        }
        return;
    }
    int mid=(b[u].l+b[u].r)>>1;
    if(pos<=mid) modify(b[u].lson,pos,opti,vi);
    else modify(b[u].rson,pos,opti,vi);
    update(u);
}

barg query(int u,int l,int r,bool type)
{
    if(b[u].l==l&&b[u].r==r)
    {
        if(type==0){
          hhh.zero=b[u].upzero;
          hhh.one=b[u].upone;
        }
        if(type==1){
          hhh.zero=b[u].dzero;
          hhh.one=b[u].done;
        }
        return hhh;
    }
    int mid=(b[u].l+b[u].r)>>1;
    if(r<=mid) return query(b[u].lson,l,r,type);
    else if(l>mid) return query(b[u].rson,l,r,type);
    barg lll=query(b[u].lson,l,mid,type);
    barg rrr=query(b[u].rson,mid+1,r,type);
    if(type==1){
    hhh.zero=((lll.zero&rrr.one)|((~lll.zero)&rrr.zero));//这个转移还是比较巧妙吧
    hhh.one=((lll.one&rrr.one)|((~lll.one)&rrr.zero));
    }
    else{
    hhh.zero=((rrr.zero&lll.one)|((~rrr.zero)&lll.zero));
    hhh.one=((rrr.one&lll.one)|((~rrr.one)&lll.zero));
    }
    return hhh;
}

void add(int op,int ed)
{
    eg[++cnt].next=head[op];
    eg[cnt].to=ed;
    head[op]=cnt;
}

void dfs1(int u,int dp)
{
    dep[u]=dp;
    vis[u]=1;
    size[u]=1;
    int w=0;
    for(int i=head[u];i!=-1;i=eg[i].next)
      if(vis[eg[i].to]==0)
      {
         fa[eg[i].to]=u;
         dfs1(eg[i].to,dp+1);
         size[u]+=size[eg[i].to];
         if(size[eg[i].to]>w)
           w=size[eg[i].to],wson[u]=eg[i].to;
      }
      vis[u]=0;
}

void dfs2(int u,int las)
{
    vis[u]=1;
    tp[u]=las;
    bl[u]=++cnt;
    modify(root,cnt,opt[u],v[u]);
    if(wson[u]!=0) dfs2(wson[u],las);
    for(int i=head[u];i!=-1;i=eg[i].next)
      if(vis[eg[i].to]==0&&eg[i].to!=wson[u])
        dfs2(eg[i].to,eg[i].to);
}

int main()
{
    memset(head,-1,sizeof(head));
    scanf("%d%d%d",&n,&m,&k);
    unsigned long long s=1;
    for(int i=1;i<=k;i++)
      inf=inf+s,s=s*2;
    for(int i=1;i<=n;i++)
      scanf("%d%llu",&opt[i],&v[i]);
    for(int i=1;i<n;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        add(x,y);add(y,x);
    }
    cnt=0;build(root,1,n);
    dfs1(1,1);cnt=0;dfs2(1,1);
    for(int i=1;i<=m;i++)
    {
        int x,q1,q2;
        unsigned long long q3;
        scanf("%d",&x);
        if(x==1)
        {
            scanf("%d%d%llu",&q1,&q2,&q3);
            queue <unsigned long long> x0;
            queue <unsigned long long> x1;
            stack <unsigned long long> y0;
            stack <unsigned long long> y1;
            while(tp[q1]!=tp[q2])
            {
                if(dep[tp[q1]]>=dep[tp[q2]]){
                    hhh=query(root,bl[tp[q1]],bl[q1],0);
                    q1=fa[tp[q1]];
                    x0.push(hhh.zero);
                    x1.push(hhh.one);
                }
                else{
                    hhh=query(root,bl[tp[q2]],bl[q2],1);
                    q2=fa[tp[q2]];
                    y0.push(hhh.zero);
                    y1.push(hhh.one);
                }
            }
            if(dep[q1]>=dep[q2])
            {
                hhh=query(root,bl[q2],bl[q1],0);
                q1=q2;
                x0.push(hhh.zero);
                x1.push(hhh.one);
            }
            else
            {
                hhh=query(root,bl[q1],bl[q2],1);
                q2=q1;
                y0.push(hhh.zero);
                y1.push(hhh.one);
            }
            unsigned long long a0=0,a1=inf;
            while(!x0.empty())
            {
                a0=(((~a0)&x0.front())|(a0&x1.front()));
                a1=(((~a1)&x0.front())|(a1&x1.front()));
                x0.pop();x1.pop();
            }
            while(!y0.empty())
            {
                a0=(((~a0)&y0.top())|(a0&y1.top()));
                a1=(((~a1)&y0.top())|(a1&y1.top()));
                y0.pop();y1.pop();
            }
            unsigned long long p,ans=0,ret=0;
            for(int j=k-1;j>=0;j--)
            {
                p=(1ll<<j);
                if((a0&p)==p)
                {
                    ret=(ret|p);
                    continue;
                }
                if((a1&p)==p&&(ans|p)<=q3)
                {
                    ans=(ans|p);
                    ret=(ret|p);
                    continue;
                }
            }
            printf("%llu\n",ret);
        }
        else
        {
            scanf("%d%d%llu",&q1,&q2,&q3);
            modify(root,bl[q1],q2,q3);
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值