单点更新+区间求最值与和_线段树

除了平时做练习赛外,现在主要学习数论与数据结构,数据结构丢了好久了,重新学习还是发现了很多问题!

/*

题意:在每个测试的第一行,是两个正整数 N 和 M ( 0< N <= 100000, 0 < M <= 100000 ),分别代表学生的数目和操作的数目。

学生ID编号分别从 1 编到 N。
第二行包含 N 个整数(范围在 0 到 100 ),代表这 N 个学生的初始成绩,其中第 i 个数代表 ID 为 i 的学生的成绩。
接下来有 M 行,每行有三个数,意思如下:
先输入一个数X,然后分两种情况:【1】【2】       (1 <= X <= 2^31-1)
【1】若X^X%999997是一个素数,则再输入两个数a,b, 
意思是将ID为 a 的学生的成绩更新成b  (1 <= a <= N,  0 <= b <= 100)  
【2】若X^X%999997不是一个素数,则再输入两个数le,ri, 
意思是输出区间【le,ri】中的学生的最低成绩、最高成绩、成绩总和 (1 <= le <= ri <= N)


Sample Input
2 8
69 24 
131744484  1 1
598487296  2 2
542004961  2 2
241081  1 2
23299929  2 36
213276816  1 2
85264  1 2
350288656  1 2


Sample Output
69 69 69
24 24 24
24 24 24
24 69 93
36 69 105
36 69 105
36 69 105
Hint
【特别说明】

【1】在本题中,我们认为0和1也是素数!!!!

*/

#include<stdio.h>
#include<string.h>
using namespace std;
#define maxn 100005
#define maxn1 1000005
#define mod 999997
#define LL __int64

struct data
{
	int l,r,minp,maxp,sump;
} tree[3*maxn];
int a[maxn];
bool prime[maxn1];

int min(int p,int q) { return p<q?p:q; }
int max(int p,int q) { return p>q?p:q; }

void Init()
{
	int i,tmp;
	memset(prime,false,sizeof(prime));
	for(i=2;i<maxn1;i++)
		if(!prime[i])
		{
			tmp=i*2;
			while(tmp<maxn1)
			{
				prime[tmp]=true;
				tmp+=i;
			}
		}
}

LL MOD(int a,int r)
{
	LL d=1,t=(LL)a;	
	while(r)
	{
		if(r%2)	d=(d*t)%mod;
		r/=2;
		t=t*t%mod;
	}
	return d%mod;
}

void BuildTree(int p,int l,int r)
{
	tree[p].l=l,tree[p].r=r;
	if(l==r)
	{
		tree[p].minp=tree[p].maxp=tree[p].sump=a[l];
		return;
	}
	int mid=(l+r)>>1;
	BuildTree(p<<1,l,mid);
	BuildTree(p<<1|1,mid+1,r);
	tree[p].minp=min(tree[p<<1].minp,tree[p<<1|1].minp);
	tree[p].maxp=max(tree[p<<1].maxp,tree[p<<1|1].maxp);
	tree[p].sump=tree[p<<1].sump+tree[p<<1|1].sump;
}

void change(int p,int i,int x)
{
	if(tree[p].l==tree[p].r)
	{
		tree[p].minp=tree[p].maxp=tree[p].sump=x;
		return;
	}
	if(i<=tree[p<<1].r)
		change(p<<1,i,x);
	else
		change(p<<1|1,i,x);
	tree[p].minp=min(tree[p<<1].minp,tree[p<<1|1].minp);
	tree[p].maxp=max(tree[p<<1].maxp,tree[p<<1|1].maxp);
	tree[p].sump=tree[p<<1].sump+tree[p<<1|1].sump;
}

data query(int p,int l,int r)
{
	if(tree[p].l==l&&tree[p].r==r)
		return tree[p];
	if(r<=tree[p<<1].r)
		return query(p<<1,l,r);
	if(l>=tree[p<<1|1].l)
		return query(p<<1|1,l,r);
	int mid=(tree[p].l+tree[p].r)>>1;
	data a=query(p<<1,l,mid),b=query(p>>1,mid+1,r);
	a.sump+=b.sump;
	a.minp=min(a.minp,b.minp);
	a.maxp=max(a.maxp,b.maxp);
	return a;
}

int main()
{
	Init();
	int n,m,i,id,x,y;
	while(~scanf("%d%d",&n,&m))
	{
		for(i=1;i<=n;i++)
			scanf("%d",&a[i]);
		BuildTree(1,1,n);
		while(m--)
		{
			scanf("%d%d%d",&id,&x,&y);
			if(!prime[MOD(id,id)]) //对x^x%mod做素数判断
				change(1,x,y);
			else
			{
				data ans;
				ans=query(1,x,y);
				printf("%d %d %d\n",ans.minp,ans.maxp,ans.sump);
			}
		}
	}
	return 0;
}


你可能感兴趣的:(单点更新+区间求最值与和_线段树)