• Codeforces1100F Ivan and Burgers 【整体二分】【线性基】


    题目分析:

    一道近似的题目曾经出现在SCOI中,那题可以利用RMQ或者线段树做,这题如果用那种做法时间复杂度会是$log$三次方的。

    采用一种类似于整体二分的方法可以解决这道题。

    将序列的线段树模型建出来,将每个询问自顶向下找,要么被分到某个区间,要么在当前区间被分成两半。

    对于某个区间$[l,r]$,可以找到一个$mid$,求出所有$[i,mid]$和$[mid+1,i]$的线性基。注意到这样的话每个数被插入线性基的次数是树高次,所以求出这些想要的线性基的复杂度是$O(nlog^2n)$。

    对于每个被分成两半的区间,可以找到一个$[i,mid]$和$[mid+1,j]$,拼起来,拼起来的复杂度是$O(log^2n)$,每个询问只被拼起来一次,所以时间复杂度是$O((n+q)log^2n)$

    代码:

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 
     4 const int maxn = 500500;
     5 
     6 int n,a[maxn],q,cal[maxn],ans[maxn];
     7 pair<int,int> qy[maxn];
     8 struct bs{int p[21];}sl[maxn],rv[maxn];
     9 
    10 void read(){
    11     scanf("%d",&n);
    12     for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    13     scanf("%d",&q);
    14     for(int i=1;i<=q;i++) scanf("%d%d",&qy[i].first,&qy[i].second);
    15 }
    16 
    17 int merge(bs alpha,bs beta){
    18     for(int i=0;i<20;i++){
    19     if(beta.p[i] == 0) continue;
    20     for(int j=i;j>=0;j--){
    21         if(!(beta.p[i]&(1<<j))) continue;
    22         if(alpha.p[j]) beta.p[i] ^= alpha.p[j];
    23         else {alpha.p[j] = beta.p[i];break;}
    24     }
    25     }
    26     int as = 0;
    27     for(int i=19;i>=0;i--)if((as^alpha.p[i]) > as) as ^= alpha.p[i];
    28     return as;
    29 }
    30 
    31 void solve(int tl,int tr,int l,int r){
    32     int mid = (tl+tr)/2;
    33     for(int i=l;i<=r;i++) rv[i] = rv[0];
    34     for(int i=mid;i>=tl;i--){
    35     sl[i] = sl[i+1]; int hh = a[i];
    36     for(int j=19;j>=0;j--){
    37         if(!((1<<j)&hh)) continue;
    38         if(sl[i].p[j]) hh ^= sl[i].p[j];
    39         else{sl[i].p[j] = hh; break;}
    40     }
    41     }
    42     for(int i=l;i<=r;i++) rv[i] = sl[qy[i].first];
    43     for(int i=tl;i<=mid;i++) sl[i] = sl[0];
    44     for(int i=mid+1;i<=tr;i++){
    45     sl[i] = sl[i-1]; int hh = a[i];
    46     for(int j=19;j>=0;j--){
    47         if(!((1<<j)&hh)) continue;
    48         if(sl[i].p[j]) hh^=sl[i].p[j];
    49         else {sl[i].p[j] = hh; break;}
    50     }
    51     }
    52     for(int i=l;i<=r;i++) ans[cal[i]] = merge(rv[i],sl[qy[i].second]);
    53     for(int i=mid+1;i<=tr;i++) sl[i] = sl[0];
    54 }
    55 
    56 void divide(int tl,int tr,int l,int r){
    57     if(l > r) return;
    58     if(tl == tr){for(int i=l;i<=r;i++) ans[cal[i]] = a[tl]; return;}
    59     int mid = (tl+tr)/2,num = l-1;
    60     for(int i=l;i<=r;i++)
    61       if(qy[i].second<=mid)num++,swap(cal[i],cal[num]),swap(qy[i],qy[num]);
    62     divide(tl,mid,l,num);
    63     int num2 = num;
    64     for(int i=num+1;i<=r;i++)
    65       if(qy[i].first>mid)num2++,swap(cal[i],cal[num2]),swap(qy[i],qy[num2]);
    66     divide(mid+1,tr,num+1,num2);
    67     solve(tl,tr,num2+1,r);
    68 }
    69 
    70 int main(){
    71     read();
    72     for(int i=1;i<=q;i++) cal[i] = i;
    73     divide(1,n,1,q);
    74     for(int i=1;i<=q;i++) printf("%d
    ",ans[i]);
    75     return 0;
    76 }
  • 相关阅读:
    统计字符
    两军交锋
    FatMouse' Trade
    A + B Problem II
    Number Sequence
    Max Sum
    类的设计
    类与对象
    面向对象思想
    第一个OC程序
  • 原文地址:https://www.cnblogs.com/Menhera/p/10286275.html
Copyright © 2020-2023  润新知