• Nikitosh 和异或 —— 一道 trie 树的题用可持久化 trie 水 然后翻车了...


    题意简介

    题目就是叫你找两个不重合的非空区间,使得这两个区间里的数异或后相加的和最大

    (看到异或,没错就决定是你了可持久化trie!)

    思路

    水一波字典树,莫名觉得这题可持久化能过,于是水了一发挂了,造了一波数据,然后发现是自己在做完一遍可持久化之后cnt 没有清零....

    其实要用可持久化trie 来做的话也就是常规操作(话说普通字典树不也是常规操作?)

    也就是前缀和往可持久化trie 上update , 然后每个 L[i]、R[i] 记录当前点为右(左)区间的最大区间异或和

    然后就是枚举断点了,考虑我们枚举到的断点前的那个区间其实是确定的(异或和最大的那个),

    那么我们拿当前断点作为第二个 区间的左端点,前面的区间由 lef 变量不断更新,最后就能累加出答案。

    于是没什么好说的了,板子题。

    代码如下

     1 //by Judge
     2 #include<iostream>
     3 #include<cstdio>
     4 using namespace std;
     5 const int M=4e5+111;
     6 //#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
     7 char buf[1<<21],*p1=buf,*p2=buf;
     8 inline int read(){
     9     int x=0,f=1; char c=getchar();
    10     for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
    11     for(;isdigit(c);c=getchar()) x=x*10+c-'0'; return x*f;
    12 }
    13 int n,cnt,a[M],L[M],R[M];
    14 int d[35],rt[M<<2],son[M<<5][2],sum[M<<5];
    15 inline void split(int k){ //换二进制
    16     int i,len=0;
    17     while(k) d[++len]=k&1,k>>=1;
    18     for(int i=len+1;i<=31;++i) d[i]=0;
    19 }
    20 inline void update(int& now,int las){ //可持久化的更新
    21     sum[now=++cnt]=sum[las]+1;
    22     int i,tmp=now;
    23     for(i=31;i;--i){
    24         son[tmp][d[i]^1]=son[las][d[i]^1],
    25         son[tmp][d[i]]=++cnt,las=son[las][d[i]],
    26         sum[tmp=cnt]=sum[las]+1;
    27     }
    28 }
    29 inline int query(int u,int v){ //询问区间内与当前数的最大异或和
    30     int ans=0,i;
    31     for(i=31;i;--i){
    32         if(sum[son[v][d[i]^1]]-sum[son[u][d[i]^1]]>0)
    33             ans|=(1<<i-1),u=son[u][d[i]^1],v=son[v][d[i]^1];
    34         else u=son[u][d[i]],v=son[v][d[i]];
    35     } return ans;
    36 }
    37 int main(){  //分函数都是常规操作(因为我都是直接搞了自己的板子)
    38     int x,lef,res=0;
    39     n=read(),++n;
    40     split(0),update(rt[1],rt[0]);
    41     for(int i=2;i<=n;++i)
    42         a[i]=read();
    43     for(int i=2,sum=0;i<=n;++i){
    44         split(sum^=a[i]),
    45         update(rt[i],rt[i-1]),
    46         L[i]=query(rt[0],rt[i]);
    47     }
    48     cnt=0,split(0),update(rt[1],rt[0]); //清零,从后往前再来一遍
    49     for(int i=n,sum=0;i>=2;--i){
    50         split(sum^=a[i]);
    51         update(rt[n-i+2],rt[n-i+1]),
    52         R[i]=query(rt[0],rt[n-i+2]);
    53     } lef=L[2];
    54     for(int i=3;i<=n;++i){ //从左到右处理答案
    55         res=max(res,lef+R[i]),
    56         lef=max(lef,L[i]);
    57     } printf("%d
    ",res); return 0;
    58 }
  • 相关阅读:
    如何在ASP.NET Core项目启动时执行异步定时任务
    计算机组成原理实验:Cache控制器设计实验 问题解决
    jenkins + gitlab 利用pipeline 完整构建项目
    利用K8S的jenkins动态slave+gitee + dockerhub实现完整的develops
    pycharm 上传代码到码云
    关于CI/CD的实践(二 提交阶段流水线)
    sonarqube-7.8 安装
    关于CI/CD的实践(一 流程规划)
    ubutun 安装nvm管理node
    关于容器的健康检查 Health Check
  • 原文地址:https://www.cnblogs.com/Judge/p/9533071.html
Copyright © 2020-2023  润新知