列表

详情


NC207431. 时间管理

描述

大司马每天日程太多,需要一个高效的数据结构进行时间管理。经过研究,他认为这个问题可以被归结如下:
给定一个长度为n的序列,第i个元素为a_i,请支持如下两种操作:
,表示将的值都与x取最大公约数,即对于,将a_i替换为gcd(a_i,x),两个数的最大公约数是能够同时整除两个数的最大数。
,询问此时的和。
请注意,操作有时间顺序,2类操作输出的是进行询问时对应区间的和。

输入描述

每个测试点仅包含一组输入数据。
第一行两个整数,表示序列长度和操作个数。
第二行n个整数,第i个整数表示a_i的初始值
接下来m行,每行为题目描述提到的的两种格式之一,表示一次操作,操作按照时间顺序给出。

输出描述

按照输入顺序,对于每个2类操作,输出一行一个整数表示对应的和。

示例1

输入:

6 4
9 9 6 2 5 1
1 1 3 6
2 2 5
1 2 5 4
2 1 6

输出:

16
10

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++14(g++5.4) 解法, 执行用时: 207ms, 内存消耗: 7028K, 提交时间: 2020-06-06 10:38:41

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int MAXN=114514+1919;
ll seg[MAXN<<2];
int a[MAXN],n,m,tag[MAXN<<2];

inline void pushup(int rt)
{
    seg[rt]=seg[rt<<1]+seg[rt<<1|1];
    if(tag[rt<<1]==tag[rt<<1|1]) tag[rt]=tag[rt<<1];
    else tag[rt]=0;
}

void build(int rt,int l,int r)
{
    if(l==r)
    {
        tag[rt]=seg[rt]=a[l];
        return;
    }
    int m=l+r>>1;
    build(rt<<1,l,m);
    build(rt<<1|1,m+1,r);
    pushup(rt);
}

void modify(int rt,int l,int r,int L,int R,int x)
{
    if(l==r)
    {
        tag[rt]=seg[rt]=__gcd(seg[rt],(long long)x);
        return;
    }
    int lst=tag[rt];
    tag[rt]=__gcd(tag[rt],x);
    if(lst&&x%lst==0) return;
    int m=l+r>>1;
    if(L<=m) modify(rt<<1,l,m,L,R,x);
    if(m<R) modify(rt<<1|1,m+1,r,L,R,x);
    pushup(rt);
}

ll query(int rt,int l,int r,int L,int R)
{
    if(L<=l&&r<=R) return seg[rt];
    int m=l+r>>1;
    ll ret=0;
    if(L<=m) ret+=query(rt<<1,l,m,L,R);
    if(R>m) ret+=query(rt<<1|1,m+1,r,L,R);
    return ret;
}

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    build(1,1,n);
    while(m--)
    {
        int op,x,y,z;
        scanf("%d%d%d",&op,&x,&y);
        if(op==2) printf("%lld\n",query(1,1,n,x,y));
        else scanf("%d",&z),modify(1,1,n,x,y,z);
    }
    return 0;
}

/*
10 10
4 4 4 4 4 4 4 4 4 4
1 1 10 8
2 1 10
*/

C++11(clang++ 3.9) 解法, 执行用时: 187ms, 内存消耗: 5516K, 提交时间: 2020-06-27 19:14:03

#include<bits/stdc++.h>
using namespace std;

int gcd(int a,int b)
{
	return b?gcd(b,a%b):a;
}
long long s,S[500005];
int y,Max[500005],Min[500005],a[120005];
void build(int L,int R,int x)
{
	if(L==R)
	{
		Max[x]=Min[x]=S[x]=a[L];
		return;
	}
	int M=(L+R)>>1;
	build(L,M,2*x),build(M+1,R,2*x+1);
	S[x]=S[2*x]+S[2*x+1];
	Max[x]=max(Max[2*x],Max[2*x+1]);
	Min[x]=min(Min[2*x],Min[2*x+1]); 
}
void update(int L,int R,int l,int r,int x)
{
	if(Max[x]==1||(Max[x]==Min[x]&&Min[x]==y))return;
	if(L==R)
	{
		Max[x]=Min[x]=S[x]=gcd(S[x],y);
		return;
	}
	int M=(L+R)>>1;
	if(M>=l)update(L,M,l,r,2*x);
	if(M<r)update(M+1,R,l,r,2*x+1);
	S[x]=S[2*x]+S[2*x+1];
	Max[x]=max(Max[2*x],Max[2*x+1]);
	Min[x]=min(Min[2*x],Min[2*x+1]); 
}
void search(int L,int R,int l,int r,int x)
{
	if(l<=L&&R<=r)
	{
		s+=S[x];
		return;
	}
	int M=(L+R)>>1;
	if(M>=l)search(L,M,l,r,2*x);
	if(M<r)search(M+1,R,l,r,2*x+1);
}
int main()
{
	int i,n,m,l,r,op;
	scanf("%d%d",&n,&m);
	for(i=1;i<=n;i++)scanf("%d",&a[i]);
	build(1,n,1);
	while(m--)
	{
		scanf("%d%d%d",&op,&l,&r);
		if(op==1)scanf("%d",&y),update(1,n,l,r,1);
		else s=0,search(1,n,l,r,1),printf("%lld\n",s);
	}
}

上一题