zoukankan      html  css  js  c++  java
  • CodeForces

    题意:给定N个数,Q次询问,求区间最大异或和。

    思路:一开始想的线性基+线段树。单次线性基合并的复杂度为20*20,结合线段树,复杂度为O(NlogN*20*20);显然,超时。

    超时代码:

    #include<bits/stdc++.h>
    #define pb push_back
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    #define rep2(i,a,b) for(int i=a;i>=b;i--)
    using namespace std;
    const int maxn=2000010;
    int a[maxn]; vector<int>G[maxn];
    void read(int &x){
        x=0; char c=getchar();
        while(c>'9'||c<'0') c=getchar();
        while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
    }
    void add(vector<int>&Now,vector<int>&p)
    {
        rep(i,0,20){
            int x=p[i]; if(!x) continue;
            rep2(j,20,0){
                if(x&(1<<j)){
                    if(Now[j]) x^=Now[j];
                    else { Now[j]=x;break;}
               }
            }
        }
    }
    void build(int Now,int L,int R)
    {
        rep(i,0,20) G[Now].pb(0);
        if(L==R){
            int x=a[L]; if(!x) return;
            rep2(j,20,0){
                if(x&(1<<j)){
                    if(G[Now][j]) x^=G[Now][j];
                    else { G[Now][j]=x;break;}
               }
            }
           return ;
        }
        int Mid=(L+R)>>1;
        build(Now<<1,L,Mid); build(Now<<1|1,Mid+1,R);
        G[Now]=G[Now<<1]; add(G[Now],G[Now<<1|1]);
    }
    void query(int Now,int L,int R,int l,int r,vector<int>& res)
    {
        if(l<=L&&r>=R) { res=G[Now]; return ;}
        int Mid=(L+R)>>1;
        rep(i,0,20) res.pb(0);
        if(l<=Mid){
             vector<int>t;
             query(Now<<1,L,Mid,l,r,t);
             res=t;
        }
        if(r>Mid) {
             vector<int>t;
             query(Now<<1|1,Mid+1,R,l,r,t);
             add(res,t);
        }
    }
    int main()
    {
        int N,M,L,R; scanf("%d",&N);
        rep(i,1,N) read(a[i]);
        build(1,1,N);
        scanf("%d",&M);
        while(M--){
            read(L); read(R);
            vector<int>t;
            query(1,1,N,L,R,t);
            int res=0; rep2(i,20,0) if((res^t[i])>res) res^=t[i];
            printf("%d
    ",res);
        }
        return 0;
    }
    View Code

    我们考虑离线,把所有询问按右端点排序,然后从左到有处理询问,对于当前询问[L,R];我们把[1,R]所有的数加入线性基,关键是对于每一位,我们保留其为位置,这里肯定是贪心地保留越后面的位置越优。 那么查询的时候,如果一个线性基里的数位置>=L,则可以考虑更新答案。

    #include<bits/stdc++.h>
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    #define rep2(i,a,b) for(int i=a;i>=b;i--)
    using namespace std;
    const int maxn=500010;
    struct in{
        int l,r,id;
        friend bool operator< (in w,in v){ return w.r<v.r;}
    }s[maxn];
    int N,Q,ans[maxn],a[maxn],p[21],pos[21];
    void add(int x,int id)
    {
        rep2(i,20,0)
          if(x&(1<<i)){
              if(!p[i]){
                  p[i]=x; pos[i]=id;
                  return ;
            }
            if(pos[i]<id) swap(p[i],x),swap(pos[i],id);
            x^=p[i];
        }
    }
    int query(int id)
    {
        int res=0;
        rep2(i,20,0) if(pos[i]>=id&&(res^p[i])>res) res^=p[i];
        return res;
    }
    int main()
    {
        scanf("%d",&N);
        rep(i,1,N) scanf("%d",&a[i]);
        scanf("%d",&Q);
        rep(i,1,Q) scanf("%d%d",&s[i].l,&s[i].r),s[i].id=i;
        sort(s+1,s+Q+1); int L=1;
        rep(i,1,Q){
              while(L<=s[i].r&&L<=N) add(a[L],L),++L;
              ans[s[i].id]=query(s[i].l);
        }
        rep(i,1,Q) printf("%d
    ",ans[i]);
        return 0;
    }

    那么同理,不难想出在线的做法,我们纪录一个前缀和 线性基,任然保留最大的位置。

    #include<bits/stdc++.h>
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    #define rep2(i,a,b) for(int i=a;i>=b;i--)
    using namespace std;
    const int maxn=500010;
    int p[maxn][21],pos[maxn][21];
    int main()
    {
        int N,Q,L,R,x;
        scanf("%d",&N);
        rep(i,1,N) {
            rep(j,0,20) p[i][j]=p[i-1][j],pos[i][j]=pos[i-1][j];
            scanf("%d",&x); int ti=i;
            rep2(j,20,0){
                if(x&(1<<j)){
                    if(!p[i][j]) { p[i][j]=x; pos[i][j]=ti; break; }
                    if(pos[i][j]<ti) swap(p[i][j],x),swap(pos[i][j],ti);
                    x^=p[i][j];
                }
            }
        }
        scanf("%d",&Q);
        rep(i,1,Q) {
            scanf("%d%d",&L,&R);
            int res=0;
            rep2(j,20,0) if(pos[R][j]>=L&&(res^p[R][j])>res) res^=p[R][j];
            printf("%d
    ",res);
        }
        return 0;
    }
  • 相关阅读:
    解决docx4j 变量替换 由于变量存在样式式或空白字符 导致替换失败问题
    redis批量删除key 远程批量删除key
    idea 集成sonarLint检查代码bugs
    mac jmeter 的使用
    tomcat配置管理员-走后门
    终端mysql Operation not permitted错误解决方案
    update使用inner join
    hibernate 三种状态的转换
    数据库中间表插入乱序
    解决https证书验证不通过的问题
  • 原文地址:https://www.cnblogs.com/hua-dong/p/10266216.html
Copyright © 2011-2022 走看看