zoukankan      html  css  js  c++  java
  • Codeforces 1100F(离线 or 在线)

    传送门

    •参考资料

      [1]:在线线性基

      [2]:离线线性基

      [3]:离线线性基

    •题意

      给你 n 个数,m 次询问;

      每次询问给定一个区间 $l,r$,求 $a_{l cdots r}$ 异或的最大值;

    •线段树+线性基

      参考了一下资料[1],学会了如何将线性基和线段树结合;

      虽然在此题中会 TLE,但是却学到了不少东西;

      首先,在建树的时候,将叶节点上的值插入到线性基中;

      在回溯的时候,通过 Merge 操作,将 pos 的儿子节点的线性基合并到 pos 的线性基上;

      类似于常规线段树中的 pushUp 操作;

      此算法可以用来做这道题:洛谷P4839

    •Code(线段树TLE版本)

      1 #include<bits/stdc++.h>
      2 using namespace std;
      3 #define ls(x) (x<<1)
      4 #define rs(x) (x<<1|1)
      5 const int maxn=5e5+50;
      6  
      7 int n,q;
      8 int a[maxn];
      9 struct Seg
     10 {
     11     int l,r;
     12     int a[25];
     13     int mid(){return l+((r-l)>>1);}
     14     void Insert(int x)
     15     {
     16         for(int i=20;i >= 0;--i)
     17         {
     18             if(x&(1<<i))
     19             {
     20                 if(!a[i])
     21                 {
     22                     a[i]=x;
     23                     return ;
     24                 }
     25                 x ^= a[i];
     26             }
     27         }
     28     }
     29     int Max()
     30     {
     31         int ans=0;
     32         for(int i=20;i >= 0;--i)
     33             ans=max(ans,ans^a[i]);
     34         return ans;
     35     }
     36 }seg[maxn<<2];
     37  
     38 Seg Marge(Seg a,Seg b)
     39 {
     40     Seg tmp=b;
     41     for(int i=0;i <= 20;++i)
     42         if(a.a[i])
     43             tmp.Insert(a.a[i]);
     44     return tmp;
     45 }
     46 void buildSeg(int l,int r,int pos)
     47 {
     48     seg[pos].l=l;
     49     seg[pos].r=r;
     50  
     51     if(l == r)
     52     {
     53         seg[pos].Insert(a[l]);
     54         return ;
     55     }
     56  
     57     int mid=l+((r-l)>>1);
     58     buildSeg(l,mid,ls(pos));
     59     buildSeg(mid+1,r,rs(pos));
     60  
     61     seg[pos]=Marge(seg[ls(pos)],seg[rs(pos)]);
     62     seg[pos].l=l;///此处要注意,因为Marge返回的结果未给l,r赋值
     63     seg[pos].r=r;
     64 }
     65 Seg Query(int l,int r,int pos)
     66 {
     67     if(seg[pos].l == l && seg[pos].r == r)
     68         return seg[pos];
     69  
     70     int mid=seg[pos].mid();
     71  
     72     if(r <= mid)
     73         return Query(l,r,ls(pos));
     74     else if(l > mid)
     75         return Query(l,r,rs(pos));
     76     else
     77         return Marge(Query(l,mid,ls(pos)),Query(mid+1,r,rs(pos)));
     78 }
     79 void Solve()
     80 {
     81     for(int i=1;i <= q;++i)
     82     {
     83         int l,r;
     84         scanf("%d%d",&l,&r);
     85  
     86         Seg ans=Query(l,r,1);
     87  
     88         printf("%d
    ",ans.Max());
     89     }
     90 }
     91 int main()
     92 {
     93 //    freopen("C:\Users\hyacinthLJP\Desktop\in&&out\contest","r",stdin);
     94     scanf("%d",&n);
     95     for(int i=1;i <= n;++i)
     96         scanf("%d",a+i);
     97     buildSeg(1,n,1);
     98  
     99     scanf("%d",&q);
    100     Solve();
    101  
    102     return 0;
    103 }
    View Code

    •离线线性基

      学会了和线段树结合后,看了看正解 线性基+贪心,果然,看不懂;

      放弃了这个解法,找了几篇离线线性基的做法(资料[2],[3]);

      大致做法是,将所有询问收集起来,并按照 r 升序排列;

      边插入 ai 边判断当前的 i 是否为当前询问的右端点;

      插入的时候,记录两个数值 base[ i ] , p[ i ],表示第 p[ i ] 个数 $a_{p_i}$ 在通过 Insert() 操作时,插入的时候插到了 base[ i ] 中;

      每次插入第 i 个数 ai 时,优先让高位的 1 用当前的位置来表示,这样可以保证高位的 1 对应的 base 值可以对最大值有贡献;

    •Code(离线)

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 const int maxn=5e5+50;
     4  
     5 int n,m;
     6 int a[maxn];
     7 struct Query
     8 {
     9     int l,r;
    10     int pos;
    11     bool operator < (const Query &obj) const
    12     {
    13         return r < obj.r;
    14     }
    15 }q[maxn];
    16 int base[30];
    17 int p[30];
    18 int ans[maxn];
    19  
    20 void Insert(int pos,int x)
    21 {
    22     for(int i=20;i >= 0;--i)
    23     {
    24         if(x&(1<<i))
    25         {
    26             if(!base[i])
    27             {
    28                 base[i]=x;
    29                 p[i]=pos;
    30                 return ;
    31             }
    32             else if(pos > p[i])///第i位的base[i]优先让p大的表示
    33             {
    34                 swap(base[i],x);
    35                 swap(p[i],pos);
    36             }
    37             x ^= base[i];
    38         }
    39     }
    40 }
    41 int Max(int k)
    42 {
    43     int l=q[k].l;
    44     int r=q[k].r;
    45  
    46     int ans=0;
    47     ///查询时,保证p大的高位base优先考虑
    48     for(int i=20;i >= 0;--i)
    49         if(p[i] >= l && p[i] <= r)
    50             ans=max(ans,ans^base[i]);
    51     return ans;
    52 }
    53 void Solve()
    54 {
    55     sort(q+1,q+m+1);
    56  
    57     int k=1;
    58     for(int i=1;i <= n;++i)
    59     {
    60         Insert(i,a[i]);
    61 
    62         while(i == q[k].r)
    63         {
    64             
    65             ans[q[k].pos]=Max(k);
    66             k++;
    67         }
    68     }
    69  
    70     for(int i=1;i <= m;++i)
    71         printf("%d
    ",ans[i]);
    72  
    73     return ;
    74 }
    75 int main()
    76 {
    77 //    freopen("C:\Users\hyacinthLJP\Desktop\in&&out\contest","r",stdin);
    78     scanf("%d",&n);
    79     for(int i=1;i <= n;++i)
    80         scanf("%d",a+i);
    81  
    82     scanf("%d",&m);
    83     for(int i=1;i <= m;++i)
    84     {
    85         scanf("%d%d",&q[i].l,&q[i].r);
    86         q[i].pos=i;
    87     }
    88  
    89     Solve();
    90  
    91     return 0;
    92 }
    View Code

    •在线线性基

      学会了离线的,再看资料[1]的正解代码时,理解起来容易了不少;

    •Code(在线)

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 const int maxn=5e5+50;
     4 
     5 int n,q;
     6 int a[maxn];
     7 int base[maxn][30];
     8 int p[maxn][30];
     9 
    10 void Insert(int pos,int x,int k)
    11 {
    12     for(int i=20;i >= 0;--i)
    13     {
    14         if(x&(1<<i))
    15         {
    16             if(!base[k][i])
    17             {
    18                 base[k][i]=x;
    19                 p[k][i]=pos;
    20             }
    21             else if(pos > p[k][i])
    22             {
    23                 swap(pos,p[k][i]);
    24                 swap(x,base[k][i]);
    25             }
    26             x ^= base[k][i];
    27         }
    28     }
    29 }
    30 int Max(int l,int r)
    31 {
    32     int ans=0;
    33     for(int i=20;i >= 0;--i)
    34         if(p[r][i] >= l)
    35             ans=max(ans,ans^base[r][i]);
    36     return ans;
    37 }
    38 void Solve()
    39 {
    40     for(int i=1;i <= n;++i)
    41     {
    42         memcpy(base[i],base[i-1],sizeof(base[i-1]));
    43         memcpy(p[i],p[i-1],sizeof(p[i-1]));
    44 
    45         Insert(i,a[i],i);
    46     }
    47 
    48     while(q--)
    49     {
    50         int l,r;
    51         scanf("%d%d",&l,&r);
    52 
    53         printf("%d
    ",Max(l,r));
    54     }
    55 }
    56 int main()
    57 {
    58     scanf("%d",&n);
    59     for(int i=1;i <= n;++i)
    60         scanf("%d",a+i);
    61     scanf("%d",&q);
    62 
    63     Solve();
    64 
    65     return 0;
    66 }
    View Code
  • 相关阅读:
    Django forms 主要的标签介绍
    DjangoForm 提交验证
    js 实现JSONP
    mssql sqlserver 批量删除所有存储过程的方法分享
    mssql sqlserver 规范使用方法分享
    MSSQL Sql加密函数 hashbytes 用法简介
    mssql sqlserver 获取指定日期为本月第几个工作日
    存储过程和函数之间有几个区别
    mssql sqlserver 视图如何加密,让第三方用户查看不到其中的SQL语句
    mssql sql语句过滤百分号的方法分享
  • 原文地址:https://www.cnblogs.com/violet-acmer/p/11354933.html
Copyright © 2011-2022 走看看