HDU-4777 Rabbit Kingdom(区间更新求和)

题目大意:给一个n个整数的数列,q次询问,每次询问区间[l,r]中与区间中其它数互质的数的个数.。

题目分析:离线处理,这里以询问区间的左端点从小到大的顺序为例。为了叙述方便,用f(l,r)表示区间[l,r]中与区间中其它数互质的数的个数.。每次用线段树或树状数组维护以 a(i)(1<=i<=n) 为左端点的所有区间的 f 值的前缀和。左端点从1~n,每变化一次,便做一次更新操作。这样,f(l,r)=sum(l)-sum(r+1)。对于数列中的每个元素a(i),预处理出其左边第一个不与他互质的数li(i),同样预处理出ri(i)。当左端点由a(i)变为a(i+1)时,要将区间[i+1,ri(i)-1]的 f 值都减1,同理,如果存在j>i并且li(j)=i,那么就要将区间[i+1,ri(j)-1]的 f 值都加1。

代码如下(用树状数组维护):

# include<iostream>
# include<cstdio>
# include<map>
# include<set>
# include<vector>
# include<cstring>
# include<algorithm>
using namespace std;

const int N=200000;

struct Node
{
	int id,l,r;
};
Node nde[N+1];
int a[N+1];
int li[N+1];
int ri[N+1];
int mark[N+1];
int ans[N+1];
int sum[N+1];
vector<int>edge[N+1];
vector<int>v[N+1];
int n;

bool comp(const Node &a,const Node &b)
{
	return a.l<b.l;
}

void init()
{
	for(int i=2;i<=N;++i)
		for(int j=i;j<=N;j+=i)
			v[j].push_back(i);
}

int lowbit(int x)
{
	return x&(-x);
}

void add(int x,int val)
{
	while(x>=1){
		sum[x]+=val;
		x-=lowbit(x);
	}
}

int getSum(int x)
{
	int res=0;
	while(x<=n){
		res+=sum[x];
		x+=lowbit(x);
	}
	return res;
}

int main()
{
	init();
	int m;
	while(scanf("%d%d",&n,&m)&&(n+m))
	{
		for(int i=1;i<=n;++i){
			scanf("%d",a+i);
			edge[i].clear();
		}
		memset(mark,0,sizeof(mark));
		for(int i=1;i<=n;++i){
			li[i]=0;
			for(int j=0;j<v[a[i]].size();++j){
				li[i]=max(li[i],mark[v[a[i]][j]]);
				mark[v[a[i]][j]]=i;
			}
		}
		memset(mark,1,sizeof(mark));
		for(int i=n;i>=1;--i){
			ri[i]=n+1;
			for(int j=0;j<v[a[i]].size();++j){
				ri[i]=min(ri[i],mark[v[a[i]][j]]);
				mark[v[a[i]][j]]=i;
			}
		}

		memset(sum,0,sizeof(sum));
		for(int i=1;i<=n;++i){
			if(li[i]){
				edge[li[i]].push_back(i);
			}else{
				add(i,1);
				if(ri[i]<=n) add(ri[i],-1);
			}
		}
		for(int i=1;i<=m;++i){
			scanf("%d%d",&nde[i].l,&nde[i].r);
			nde[i].id=i;
		}

		int id=1;
		sort(nde+1,nde+m+1,comp);

		for(int i=1;i<=n&&id<=m;++i){
			while(nde[id].l==i){
				ans[nde[id].id]=(getSum(nde[id].l)-getSum(nde[id].r+1));
				++id;
			}
			add(i,-1);
			if(ri[i]<=n) add(ri[i],1);
			for(int j=0;j<edge[i].size();++j){
				int x=edge[i][j];
				add(x,1);
				if(ri[x]<=n) add(ri[x],-1);
			}
		}
		for(int i=1;i<=m;++i) printf("%d\n",ans[i]);
	}
	return 0;
}

  

时间: 2024-11-09 05:26:18

HDU-4777 Rabbit Kingdom(区间更新求和)的相关文章

hdu 4777 Rabbit Kingdom(树状数组)

题目链接:hdu 4777 Rabbit Kingdom 题目大意:一个兔子王国,有N只兔子,每只兔子有一个重量,如果两只兔子的重量不互质,那么就会干架,现在国王想将l r之间的兔子关进监狱,它想知道会有多少只兔子不会和别的兔子干架. 解题思路:预处理出每只兔子的L,R表示向左和向右最近会与该兔子发生冲突的兔子,预处理的时候只要将每只兔子的重量分解成质因子后遍历两遍. 对于询问,将询问按照右区间排序,碰到i,则L位置+1,碰到R,则i位置+1,L位置-1.(如果L ≤ l && r ≤ R

HDU 4777 Rabbit Kingdom(树状数组)

HDU 4777 Rabbit Kingdom 题目链接 题意:给定一些序列,每次询问一个区间,求出这个区间和其他数字都互质的数的个数 #include <cstdio> #include <cstring> #include <algorithm> #include <vector> using namespace std; const int INF = 0x3f3f3f3f; typedef long long ll; const ll N = 200

hdu 4777 Rabbit Kingdom(离线树状数组&amp;思维)

Rabbit Kingdom Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 964    Accepted Submission(s): 315 Problem Description Long long ago, there was an ancient rabbit kingdom in the forest. Every rab

HDU 4777 Rabbit Kingdom

素因子分解,树状数组.$ACM/ICPC$ $2013$杭州区域赛$H$题. 首先需要处理出数字$a[i]$左边最远到$L[i]$,右边最远到$R[i]$区间内所有数字都与$a[i]$互质. 那么对于左端点在$[L[i],i]$并且右端点在$[i,R[i]]$的询问,$a[i]$就可以作出一个贡献. 接下来的问题就可以转化为二维平面上有很多矩形,每次询问一个点被多少矩形覆盖.可以离线操作,类似于扫描线的思想做就可以了. 素因子分解需要一开始把$20$万个数字都处理好,避免每组测试数据内重复处理.

hdu 4777 Rabbit Kingdom (离线树状数组)

题目大意: 给出m个查询,查询出[ l - r] 之间去 这个区间所有的数都互质的数有多少个. 思路分析: 首先我们处理出来每一个位置,左边和右边第一个与之不互质的数的位置.记在pre 和 next下.这个方法用分解质因数就好. 一个区间内的答案,等于这个区间的所有数减去有与之互质数的个数. 现在要统计的就是 1.对于一个给定的查询[l,r] 区间,统计有多少个 i (l<= i  <=r) 的pre[i] 或 next[i]在[l,r]内. 2.对于一个给定的查询[l,r]区间,统计有多个个

HDU 4777 Rabbit Kingdom --容斥原理+树状数组

题意: 给一个数的序列,询问一些区间,问区间内与区间其他所有的数都互质的数有多少个. 解法: 直接搞有点难, 所谓正难则反,我们求区间内与其他随便某个数不互质的数有多少个,然后区间长度减去它就是答案了. 那么怎么求区间内与区间其他某个数不互质的数的个数(记为cnt)呢? 我们用L[i],R[i]表示在整个序列中左边与 i 最近的与 i 不互质的数的位置,R[i]表示右边的,L[i],R[i]我们可以正反扫一遍顺便分解因子,用个pos[]记录很方便地求出.那么区间内的cnt为L[i]或R[i]在区

HRBUST 1161 树状数组区间更新求和

Leyni Time Limit: 3000 MS Memory Limit: 65536 K Total Submit: 267(64 users) Total Accepted: 82(57 users) Rating: Special Judge: No Description Leyni被人掳走,身在水深火热之中... 小奈叶为了拯救Leyni,独自一人前往森林深处从静竹手中夺回昏迷中的Leyni. 历经千辛万苦,小奈叶救出了Leyni,但是静竹为此极为恼怒,决定对他们发起最强烈的进攻.

PKU A Simple Problem with Integers (线段树区间更新求和)

题意:典型的线段树C,Q问题,有n个数a[i] (1~n),C, a, b,c在[a,b]区间增加c Q a b 求[a,b]的和. #include<cstdio> #include<stdlib.h> #include<string.h> #include<string> #include<map> #include<cmath> #include<iostream> #include <queue> #i

FZU1608 Huge Mission 线段树lazy区间更新+求和

就这破题目坑了我一个大晚上,直到今天一觉醒过来才搞定,原因之一:这题目的题意真的是太狗了,还不如直接看着案例猜来的快啊, 题意:给了你一些区间,x,y,第三个参数w是效率,代表这段时间他的单位时间效率,效率总和就是 (y-x)*w,然后有的时间段会被重复啊,比如前面给了1,4,1,后面又给了2,4,3他们为了是的时间段1,4的效率总和最大肯定是选择  2,4区间的效率值选择3,意思就是后面出现更好的情况就覆盖前面的,问你总得最大效率和 当然这题目坑的原因还有一个就是以前学习线段树 做的时候都是看

POJ 2777 &amp;&amp; ZOJ 1610 &amp;&amp;HDU 1698 --线段树--区间更新

直接将这3题 放一起了  今天在做线段树的东西 这3个都是区间更新的 查询方式互相不同 反正都可以放到一起吧 直接先上链接了 touch me touch me touch me 关于涉及到区间的修改 -- 区间更新的话 分为 增减 或者 修改 主要就是个 laze 标记 就是延迟更新 对于区间更新的写法 一般是有2种 其一 仔细划分到每个细小的区间    另一 粗略划分 反正 ==我的代码里会给出2种写法 看自己喜好 hdu 1 //线段树 成段更新 ---> 替换 根结点的查询 2 3 #i