Rabbit Kingdom LA6461

O(n*logn)预处理出对于每个位置i,最大的left[i], right[i], 使得arr[left[i]...i...right[i]]与arr[i]互质(当然arr[i]与其本身不互质不考虑),利用链表记录一些信息,然后用树状数组维护后缀和,更新答案。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <queue>
#include <algorithm>
#include <vector>
#include <cstring>
#include <stack>
#include <cctype>
#include <utility>   
#include <map>
#include <string>  
#include <climits> 
#include <set>
#include <string>    
#include <sstream>
#include <utility>   
#include <ctime>
#include <bitset>
#include <iomanip>
//#pragma comment(linker, "/STACK:102400000,102400000")

using std::priority_queue;
using std::vector;
using std::swap;
using std::stack;
using std::sort;
using std::max;
using std::min;
using std::pair;
using std::map;
using std::string;
using std::cin;
using std::cout;
using std::set;
using std::queue;
using std::string;
using std::stringstream;
using std::make_pair;
using std::getline;
using std::greater;
using std::endl;
using std::multimap;
using std::deque;
using std::unique;
using std::lower_bound;
using std::random_shuffle;
using std::bitset;
using std::upper_bound;
using std::multiset;
using std::ios;

typedef long long LL;
typedef unsigned long long ULL;
typedef unsigned UN;
typedef pair<ULL, ULL> PAIR;
typedef multimap<int, int> MMAP;
typedef long double LF;

const int MAXN(200010);
const int MAXM(310);
const int MAXE(310);
const int MAXK(6);
const int HSIZE(131313);
const int SIGMA_SIZE(26);
const int MAXH(18);
const int INFI((INT_MAX-1) >> 1);
const ULL BASE(31);
const LL LIM(1e13);
const int INV(-10000);
const int MOD(1000000007);
const double EPS(1e-7);
const LF PI(acos(-1.0));

template<typename T> inline void checkmax(T &a, T b){if(b > a) a = b;}
template<typename T> inline void checkmin(T &a, T b){if(b < a) a = b;}
template<typename T> inline T ABS(const T &a){return a < 0? -a: a;}

struct BIT
{
	int arr[MAXN], size;
	void init(int s)
	{
		size = s;
		memset(arr+1, 0, sizeof(arr[0])*s);
	}
	void updata(int ti, int tv)
	{
		for(; ti > 0; ti -= ti&-ti) arr[ti] += tv;
	}
	int query(int ti)
	{
		int ret = 0;
		for(; ti <= size; ti += ti&-ti) ret += arr[ti];
		return ret;
	}
} bt;

struct EDGE
{
	int u, v;
	EDGE *next;
};
bool is[MAXN]; 
EDGE *rec[MAXN];
EDGE eg1[600100], *rear1;
void prepro()
{
	memset(is, -1, sizeof(is));
	is[1] = false;
	for(LL i = 2; i <= 200000; ++i)
		if(is[i])
		{
			rear1->v = i;
			rear1->next = rec[i];
			rec[i] = rear1++;
			for(LL j = i+i; j <= 200000; j += i)
			{
				rear1->v = i;
				rear1->next = rec[j];
				rec[j] = rear1++;
				is[j] = false;
			}
		}
}

int aid[MAXN], left[MAXN], right[MAXN];
int arr[MAXN];
EDGE *que[MAXN];
EDGE eg2[MAXN], *rear2;
EDGE *tab[MAXN];
EDGE eg3[MAXN], *rear3;
int ans[MAXN];

int main()
{
//    freopen("d:\\in.txt","r",stdin);
//    freopen("d:\\out.txt","w",stdout);
	rear1 = eg1;
	prepro();
	int n, m;
	while(scanf("%d%d", &n, &m), n+m)
	{
		rear2 = eg2;
		rear3 = eg3;
		int temp = 1;
		for(int i = 1; i <= n; ++i) 
		{
			scanf("%d", arr+i);
			que[i] = tab[i] = 0;
			checkmax(temp, arr[i]);
		}
		for(int i = 0; i <= temp; ++i) aid[i] = 0;
		for(int i = 1; i <= n; ++i)
		{
			int mx = 0;
			for(EDGE *p = rec[arr[i]]; p; p = p->next)
			{
				checkmax(mx, aid[p->v]);
				aid[p->v] = i;
			}
			left[i] = mx+1;
		}
		for(int i = 0; i <= temp; ++i) aid[i] = n+1;
		for(int i = n; i >= 1; --i)
		{
			int mi = n+1;
			for(EDGE *p = rec[arr[i]]; p; p = p->next)
			{
				checkmin(mi, aid[p->v]);
				aid[p->v] = i;
			}
			right[i] = mi-1;
			rear3->u = left[i];
			rear3->v = i;
			rear3->next = tab[right[i]];   
			tab[right[i]] = rear3++;
		}
		int ql, qr;
		for(int i = 0; i < m; ++i)
		{
			scanf("%d%d", &ql, &qr);
			rear2->u = ql;
			rear2->v = i;
			rear2->next = que[qr];
			que[qr] = rear2++;
		}
		bt.init(n);
		for(int i = 1; i <= n; ++i) //更新答案时保证qr <= right[i]
		{
			if(left[i] > 1) bt.updata(left[i]-1, -1);
			bt.updata(i, 1);
			for(EDGE *p = que[i]; p; p = p->next) ans[p->v] = bt.query(p->u);
			for(EDGE *p = tab[i]; p; p = p->next)  //对于qr > right[k]的询问, arr[k]不会再有贡献了,所以修改回去 
			{
				if(p->u > 1) bt.updata(p->u-1, 1);
				bt.updata(p->v, -1);
			}
		}
		for(int i = 0; i < m; ++i) printf("%d\n", ans[i]);
	}
	return 0;
}





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值