Kattis - bitwise Bitwise (RMQ+尺取+树上dfs)
Posted asdfsag
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Kattis - bitwise Bitwise (RMQ+尺取+树上dfs)相关的知识,希望对你有一定的参考价值。
题意:有一个长度为n的序列,让你把它分成k段,段内元素取or,段间取and,求能够得到的最大值。
这个算法是我和xz场上yy出来的,然而时间不够了没写出来,而且时间复杂度是$O(nlogn+nlogA)$的比官方题解都要低...(但是常数大了点)
设最大值为ans,我们假设S&ans=S,看看S能否用k条线段凑出来,则将原问题转化成了一个判定问题。从高到低一位一位地考虑,最多只需进行$O(logA)$次判定。
如何进行判定呢?
首先将原数组复制一倍接到后面,然后进行两次尺取。第一次求出每个左端点l所对应的能够覆盖S的最小的右端点r并把它作为一条线段放进数组里(能够覆盖S的意思是S的每一位上的1都可以在[l,r]区间里的某个元素中取到,可以用RMQ预处理区间or然后$O(1)$判断),第二次则对这些线段进行尺取,求出每条线段右边第一条和它不相交的线段,将每条线段与这样的线段连边,可以得到一棵树(或者森林,若为森林则将所有树和一个虚节点连边即可变成一棵树),只需要检查一下这棵树上是否有一个结点的l和与它距离为k的父亲结点的r的区间长度r-l+1是否小于n,从根节点dfs一遍即可。
代码:(我写了两份,第一份怕爆栈所以手写了数组模拟栈,第二份是普通的dfs)
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int N=1e6+10; 5 int n,k,a[N],ST[N][20],Log[N],nl,hd[N],ne,q[N],tp; 6 void build() 7 for(int i=1; i<=2*n; ++i)ST[i][0]=a[i]; 8 for(int k=1; k<=Log[2*n]; ++k) 9 for(int i=1; i+(1<<k)-1<=2*n; ++i) 10 ST[i][k]=ST[i][k-1]|ST[i+(1<<(k-1))][k-1]; 11 12 int qry(int L,int R) 13 int k=Log[R-L+1]; 14 return ST[L][k]|ST[R-(1<<k)+1][k]; 15 16 struct D int l,r; line[N]; 17 struct E int v,nxt; e[N]; 18 struct ND int u,dep; sta[N]; 19 void addedge(int u,int v) e[ne]= v,hd[u],hd[u]=ne++; 20 bool dfs() 21 sta[tp=0]= nl,0; 22 while(~tp) 23 int u=sta[tp].u,dep=sta[tp--].dep; 24 q[dep]=u; 25 if(dep>=k&&line[q[dep-k+1]].r-line[u].l+1<=n)return 1; 26 for(int i=hd[u]; ~i; i=e[i].nxt)sta[++tp]= e[i].v,dep+1; 27 28 return 0; 29 30 bool ok(int S) 31 nl=0; 32 for(int i=1,j=1; i<=2*n; ++i) 33 if(j<i)j=i; 34 for(; j<=2*n&&(qry(i,j)&S)!=S; ++j); 35 if(j<=2*n)line[nl++]= i,j; 36 37 for(int i=0; i<=nl; ++i)hd[i]=-1; 38 ne=0; 39 for(int i=0,j=0; i<nl; ++i) 40 for(; j<nl&&line[j].l<=line[i].r; ++j); 41 addedge(j,i); 42 43 return dfs(); 44 45 int solve() 46 int ret=0; 47 for(int i=30; i>=0; --i)if(ok(ret|(1<<i)))ret|=1<<i; 48 return ret; 49 50 int main() 51 Log[0]=-1; 52 for(int i=1; i<N; ++i)Log[i]=Log[i>>1]+1; 53 scanf("%d%d",&n,&k); 54 for(int i=1; i<=n; ++i)scanf("%d",&a[i]); 55 for(int i=1; i<=n; ++i)a[i+n]=a[i]; 56 build(); 57 printf("%d\n",solve()); 58 return 0; 59
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int N=1e6+10; 5 int n,k,a[N],ST[N][20],Log[N],nl,hd[N],ne,q[N]; 6 void build() 7 for(int i=1; i<=2*n; ++i)ST[i][0]=a[i]; 8 for(int k=1; k<=Log[2*n]; ++k) 9 for(int i=1; i+(1<<k)-1<=2*n; ++i) 10 ST[i][k]=ST[i][k-1]|ST[i+(1<<(k-1))][k-1]; 11 12 int qry(int L,int R) 13 int k=Log[R-L+1]; 14 return ST[L][k]|ST[R-(1<<k)+1][k]; 15 16 struct D int l,r; line[N]; 17 struct E int v,nxt; e[N]; 18 void addedge(int u,int v) e[ne]= v,hd[u],hd[u]=ne++; 19 bool dfs(int u,int dep) 20 q[dep]=u; 21 if(dep>=k&&line[q[dep-k+1]].r-line[u].l+1<=n)return 1; 22 for(int i=hd[u]; ~i; i=e[i].nxt)if(dfs(e[i].v,dep+1))return 1; 23 return 0; 24 25 bool ok(int S) 26 nl=0; 27 for(int i=1,j=1; i<=2*n; ++i) 28 if(j<i)j=i; 29 for(; j<=2*n&&(qry(i,j)&S)!=S; ++j); 30 if(j<=2*n)line[nl++]= i,j; 31 32 for(int i=0; i<=nl; ++i)hd[i]=-1; 33 ne=0; 34 for(int i=0,j=0; i<nl; ++i) 35 for(; j<nl&&line[j].l<=line[i].r; ++j); 36 addedge(j,i); 37 38 return dfs(nl,0); 39 40 int solve() 41 int ret=0; 42 for(int i=30; i>=0; --i)if(ok(ret|(1<<i)))ret|=1<<i; 43 return ret; 44 45 int main() 46 Log[0]=-1; 47 for(int i=1; i<N; ++i)Log[i]=Log[i>>1]+1; 48 scanf("%d%d",&n,&k); 49 for(int i=1; i<=n; ++i)scanf("%d",&a[i]); 50 for(int i=1; i<=n; ++i)a[i+n]=a[i]; 51 build(); 52 printf("%d\n",solve()); 53 return 0; 54
以上是关于Kattis - bitwise Bitwise (RMQ+尺取+树上dfs)的主要内容,如果未能解决你的问题,请参考以下文章