1. 程式人生 > >【線段樹】2019雅禮集訓 sequence

【線段樹】2019雅禮集訓 sequence

題目:

給出k,和一個長度為n的序列A

有q次詢問,

每次詢問 A l , A l + 1

, A l + 2 ,
A r A_l,A_{l+1},A_{l+2}……,A_{r} 中,有多少連續的子序列的 & \&
只和為k的倍數。


分析:

比較水的線段樹題。

眾所周知,與運算的字首和最多隻有 l o g A i logA_i 個值,所以可以預處理出來,以每個節點為右端點時,其左端點在哪些區間內時,與運算之後的結果完全相同。

然後,離線操作。這道題就變成了:區間+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]);
}