世界真的很大
很多正解其实本来都是暴力,但是莫名其妙地过了,然后分析一波复杂度貌似没有问题,然后就是正解了
线段树的运用的却有很多,其实只要要处理的问题满足区间合并的性质就行了
在遇见新的需要处理的问题时,要优先考虑他的信息对于询问而言能不能区间合并
如果可以那就可以区间合并了
如果不行的话就只能想其他办法了,或者暴力上。
有些时候暴力并不一定不是正解,要好好分析题目性质,计算一波复杂度
看题先:
description:
长度为n的非负整数数列,3种操作
1. 求[L,R]所有数的和。
2. 将[L,R]中所有数都mod x。
3. 将a[i]修改为v。
n,m≤100000
input
第一行两个整数n,m,表示数列元素个数和操作数
接下来n个数,表示序列
接下来m行,每行开头一个整数表示操作
output
对于每一个询问操作,输出一个整数表示答案
如果没有2操作的话,还是很简单的线段树裸题,单点修改,区间查询
现在考虑怎么处理这个取模的问题
对于一段区间,如果取模的数比这段区间所有的数都大,那取模就是没有意义的,就是说,如果取模的数比区间最大的数还大,那么就不用取模了,所以我们在线段树里再记录一个区间最大值
考虑每次取模,对于每一个数x,取模y,x mod y的值必然比y小,如果y小于x/2,那x就变得小于x/2,如果y大于x/2,x剩下的部分也比x/2少,x也会变得比x/2小
那么就是说x每次取模都会变得比x/2小,就是说,对于一个数x,有效的取mod最多进行logx次,一共只会进行nlogn次取模,那么就算对所有的数取模,这个时间复杂度都是可以接受的
分析一波之后,发现,直接暴力去取模是可行的。
那么我们对于每个区间记录一个最大值,如果取模的数大于最大值,就不管,如果小于最大值,就暴力取模
完整代码:
#include
#include
using namespace std;
typedef long long dnt;
struct node
{
dnt sum,big;
node *ls,*rs;
void update()
{
sum=ls->sum+rs->sum;
big=max(ls->big,rs->big);
}
}pool[2000010],*tail=pool,*root,*null;
dnt a[100010];
int n,m;
void init()
{
null=++tail;
null->sum=null->big=0;
null->ls=null->rs=null;
}
node *newnode()
{
node *nd=++tail;
nd->ls=nd->rs=null;
nd->sum=nd->big=0;
return nd;
}
node *build(int lf,int rg)
{
node *nd=newnode();
if(lf==rg)
{
nd->big=nd->sum=a[lf];
return nd;
}
int mid=(lf+rg)>>1;
nd->ls=build(lf,mid);
nd->rs=build(mid+1,rg);
nd->update();
return nd;
}
void modify(node *nd,int lf,int rg,int pos,dnt delta)
{
if(lf==rg)
{
nd->sum=nd->big=delta;
return ;
}
int mid=(lf+rg)>>1;
if(pos<=mid) modify(nd->ls,lf,mid,pos,delta);
else modify(nd->rs,mid+1,rg,pos,delta);
nd->update();
}
void modifz(node *nd,int lf,int rg,int L,int R,dnt delta)
{
if(nd->bigreturn ;
if(lf==rg)
{
nd->sum%=delta,nd->big%=delta;
return ;
}
int mid=(lf+rg)>>1;
if(L<=mid) modifz(nd->ls,lf,mid,L,R,delta);
if(R>mid) modifz(nd->rs,mid+1,rg,L,R,delta);
nd->update();
}
dnt query(node *nd,int lf,int rg,int L,int R)
{
if(L<=lf&&rg<=R)
return nd->sum;
int mid=(lf+rg)>>1;
dnt rt=0;
if(L<=mid) rt+=query(nd->ls,lf,mid,L,R);
if(R>mid) rt+=query(nd->rs,mid+1,rg,L,R);
return rt;
}
int main()
{
init();
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%lld",&a[i]);
root=build(1,n);
while(m--)
{
int opt,x,y;
dnt z;
scanf("%d",&opt);
if(opt==3)
{
scanf("%d%lld",&x,&z);
modify(root,1,n,x,z);
}
else if(opt==2)
{
scanf("%d%d%lld",&x,&y,&z);
modifz(root,1,n,x,y,z);
}
else if(opt==1)
{
scanf("%d%d",&x,&y);
printf("%lld\n",query(root,1,n,x,y));
}
}
return 0;
}
/*
Whoso pulleth out this sword from this stone and anvil is duly born King of all England
*/
嗯,就是这样