【線段樹】2019雅禮集訓 sequence
阿新 • • 發佈:2019-01-12
題目:
給出k,和一個長度為n的序列A
有q次詢問,
每次詢問
中,有多少連續的子序列的
只和為k的倍數。
分析:
比較水的線段樹題。
眾所周知,與運算的字首和最多隻有 個值,所以可以預處理出來,以每個節點為右端點時,其左端點在哪些區間內時,與運算之後的結果完全相同。
然後,離線操作。這道題就變成了:區間+1,區間求和。果斷線段樹水過。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define SF scanf
#define PF printf
#define MAXN 100010
using namespace std;
void Read(int &x){
char c;
while(c=getchar(),c!=EOF&&(c<'0'||c>'9'));
x=c-'0';
while(c=getchar(),c!=EOF&&c>='0'&&c<='9')
x=x*10+c-'0';
}
typedef long long ll;
int nxt[MAXN][32];
int a[MAXN],k,n,q;
ll ans[MAXN*5],res;
struct node{
int l,r,id;
node () {}
node (int l1,int r1,int id1):l(l1),r(r1),id(id1) {}
bool operator <(const node &a) const {
return r<a.r;
}
}que[MAXN*5];
int pos[33];
ll tree[MAXN*4],tag[MAXN*4];
void change(int l,int r,int id,int l1,int r1){
if(l>=l1&&r<=r1){
tag[id]++;
tree[id]+=(r-l+1);
return ;
}
int mid=(l+r)>>1;
if(l1<=mid)
change(l,mid,id<<1,l1,r1);
if(r1>mid)
change(mid+1,r,id<<1|1,l1,r1);
tree[id]=tree[id<<1]+tree[id<<1|1]+tag[id]*(r-l+1);
}
ll query(int l,int r,int id,int l1,int r1){
if(l>=l1&&r<=r1)
return tree[id];
int mid=(l+r)>>1;
ll res=0;
if(l1<=mid)
res+=query(l,mid,id<<1,l1,r1);
if(r1>mid)
res+=query(mid+1,r,id<<1|1,l1,r1);
res+=(min(r,r1)-max(l,l1)+1)*tag[id];
return res;
}
void add(int x){
int cnt=0;
for(int i=0;i<31;i++)
if(a[x]&(1<<i))
pos[++cnt]=nxt[x][i];
sort(pos+1,pos+1+cnt);
int now=a[x],las=x;
pos[cnt+1]=x;
// PF("[%d(%d %d)]:",x,cnt,nxt[x][0]);
for(int i=cnt;i>=1;i--){
int now1=now&a[pos[i]];
if(now1%k!=0&&now%k==0){
change(1,n,1,pos[i]+1,las);
// PF("[%d %d]",pos[i+1],pos[i]+1);
}
if(now1%k==0&&now%k!=0)
las=pos[i];
now=now1;
}
if(now%k==0&&las!=0){
change(1,n,1,1,las);
// PF("[%d %d]",pos[1],1);
}
// PF("\n");
}
int main(){
// SF("%d%d%d",&n,&q,&k);
Read(n),Read(q),Read(k);
for(int i=1;i<=n;i++)
Read(a[i]);
// SF("%d",&a[i]);
for(int i=1;i<=n;i++)
for(int j=0;j<31;j++){
nxt[i][j]=nxt[i-1][j];
if((a[i]&(1<<j))==0)
nxt[i][j]=i;
}
for(int i=1;i<=q;i++){
Read(que[i].l),Read(que[i].r);
// SF("%d%d",&que[i].l,&que[i].r);
que[i].id=i;
}
sort(que+1,que+1+q);
int las=0;
for(int i=1;i<=q;i++){
while(las<que[i].r){
las++;
add(las);
}
ans[que[i].id]=query(1,n,1,que[i].l,n);
}
for(int i=1;i<=q;i++)
PF("%lld\n",ans[i]);
}