zoukankan      html  css  js  c++  java
  • 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 }
  • 相关阅读:
    编译预处理指令:文件包含指令、宏定义指令、条件编译指令
    多文件协作,extern、static、头文件
    函数间参数传递的3种方式
    函数的定义与调用
    编码标准:ASCII、GBK、Unicode(UTF8、UTF16、UTF32)
    插入字符
    Windows Vista for Developers——第四部分:用户帐号控制(User Account Control,UAC)
    C# 获取QQ好友列表信息的实现
    C# 获取QQ群数据的实现
    QQ登陆功能的实现2
  • 原文地址:https://www.cnblogs.com/Judge/p/9533071.html
Copyright © 2011-2022 走看看