欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 编程资源 > 编程问答 >内容正文

编程问答

牛客多校5 - Interval(主席树)

发布时间:2024/4/11 编程问答 60 豆豆
生活随笔 收集整理的这篇文章主要介绍了 牛客多校5 - Interval(主席树) 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

题目链接:点击查看

题目大意:给出一个长度为 n 的数列 a ,规定函数 f( l , r ) = a[ l ] & a[ l + 1 ] & ... & a[ r ] ,在规定set s( l , r ) = { f( a , b ) | l <= a <= b <= r } ,对于 q 次询问,每次询问回答 s( l , r )

题目分析:根据位运算的性质,可以知道每一位都是相互独立的,再根据与运算的性质,可以知道,当左端点或者右端点的其中一个端点在固定之后,不同的 f( l , r ) 最多有 logn 个,因为假设当前端点二进制下全部为 1 ,因为 f 函数是需要取连续的一段子数列,所以每次减少一个 1 ,最多减少 logn 次在二进制下就变为 0 了

假设数列为 a[ 1 ] , a[ 2 ] , a[ 3 ] ... a[ n - 1 ] , a[ n ] ,对于一个位置 i 来说,记录其全部的后缀,也就是:

  • a[ 1 ] & a[ 2 ] & ... & a[ i - 1 ] & a[ i ]
  • a[ 2 ] & a[ 3 ] & ... & a[ i - 1 ] & a[ i ]
  • a[ 3 ] & a[ 4 ] & ... & a[ i - 1 ] & a[ i ]
  • ......
  • a[ i - 1 ] & a[ i ]
  • a[ i ]
  • 虽然一共有 i 个后缀,但根据上一段分析的性质,当固定了右端点 i 后,最多只会有 logn 个不同的数字

    到此为止,剩下的就可以用主席树统计区间有多少个不同的数字的那个模板来实现了

    代码:

    #include<iostream> #include<cstdio> #include<string> #include<ctime> #include<cmath> #include<cstring> #include<algorithm> #include<stack> #include<climits> #include<queue> #include<map> #include<set> #include<sstream> #include<cassert> #include<bitset> #include<unordered_map> using namespace std;typedef long long LL;typedef unsigned long long ull;const int inf=0x3f3f3f3f;const int N=1e5+100;unordered_map<int,int>mp,temp,pre;struct Node {int l,r;int sum; }tree[N*150];int cnt,root[N];void init() {root[0]=0;tree[0].l=tree[0].r=tree[0].sum=0;cnt=1; }void update(int pos,int &k,int l,int r,int val) {tree[cnt++]=tree[k];k=cnt-1;tree[k].sum+=val;if(l==r)return;int mid=l+r>>1;if(pos<=mid)update(pos,tree[k].l,l,mid,val);elseupdate(pos,tree[k].r,mid+1,r,val); }int query(int rt,int l,int r,int L,int R)//[l,r]:目标区间,[L,R]:当前区间 {if(R<l||L>r)return 0;if(L>=l&&R<=r)return tree[rt].sum;int mid=L+R>>1;return query(tree[rt].l,l,r,L,mid)+query(tree[rt].r,l,r,mid+1,R); }int main() { #ifndef ONLINE_JUDGE // freopen("data.in.txt","r",stdin); // freopen("data.out.txt","w",stdout); #endif // ios::sync_with_stdio(false);init();int n;scanf("%d",&n);for(int i=1;i<=n;i++){root[i]=root[i-1];int x;scanf("%d",&x);mp[x]=i;temp.clear();for(auto it=mp.begin();it!=mp.end();it++){int fir=it->first,sec=it->second;temp[x&fir]=max(temp[x&fir],sec);}for(auto it=temp.begin();it!=temp.end();it++){int fir=it->first,sec=it->second;if(pre[fir])update(pre[fir],root[i],1,n,-1);pre[fir]=sec;update(pre[fir],root[i],1,n,1);}mp=temp;}int q,ans=0;scanf("%d",&q);while(q--){int l,r;scanf("%d%d",&l,&r);l=(l^ans)%n+1;r=(r^ans)%n+1;if(l>r)swap(l,r);printf("%d\n",ans=query(root[r],l,r,1,n));}return 0; }

     

    总结

    以上是生活随笔为你收集整理的牛客多校5 - Interval(主席树)的全部内容,希望文章能够帮你解决所遇到的问题。

    如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。