算法随笔——势能线段树
The Child and Sequence
修改为区间取模,维护区间和。
做法是线段树上,当前区间max若小于模数,则直接跳过。
可以发现取模这一操作不会超过 \(\log n\) 次有效操作。
因为 \(a mod b <= a/2\)
证明如下 :
\(b > a/2,则a mod b <= a/2\)
$ b <= a/2$,a mod b < b <= a/2
// LUOGU_RID: 170637787
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define INF 0x3f3f3f3f
#define re register
#define int ll
#define PII pair<int,int>
int read()
{
int f=1,k=0;char c = getchar();
while(c <'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9')k=(k<<1)+(k<<3)+(c^48),c=getchar();
return k*f;
}
const int N = 3e5+5;
int n,m,a[N<<4];
int mx[N<<4],sum[N<<4];
void pushup(int k)
{
mx[k] = max(mx[k<<1],mx[k<<1|1]);
sum[k] = sum[k<<1] + sum[k<<1|1];
}
void modify2(int k,int l,int r,int x,int v)
{
if (x > r || x < l) return;
if (l == r)
{
mx[k] = v;
sum[k] = v;
return;
}
int mid = l +r >> 1;
modify2(k<<1,l,mid,x,v);
modify2(k<<1|1,mid + 1,r,x,v);
pushup(k);
}
void modify1(int k,int l,int r,int x,int y,int v)
{
if (x > r || y < l) return;
if (mx[k] < v) return;
// cout << k << '/' << mx[k] << endl;
if (l == r)
{
mx[k] %= v;
sum[k] %= v;
return;
}
int mid = l +r >> 1;
modify1(k<<1,l,mid,x,y,v);
modify1(k<<1|1,mid+1,r,x,y,v);
pushup(k);
}
int query(int k,int l,int r,int x,int y)
{
if (x > r || y < l) return 0;
if (x <= l && r <= y) return sum[k];
int mid =l + r>>1;
return query(k << 1,l,mid,x,y) + query(k << 1 | 1,mid + 1,r,x,y);
}
signed main()
{
cin >> n >> m;
for (int i = 1;i <= n;i++) a[i] = read(),modify2(1,1,n,i,a[i]);
while (m--)
{
int op = read(),l = read(),r = read();
if (op == 1)
{
if (l > r) swap(l,r);
printf("%lld\n",query(1,1,n,l,r));
}
else if (op == 2)
{
if (l > r) swap(l,r);
int x = read();
modify1(1,1,n,l,r,x);
}
else modify2(1,1,n,l,r);
}
return 0;
}

浙公网安备 33010602011771号