MongoDB遠端定時備份與還原
阿新 • • 發佈:2021-11-08
Acwing 245. 你能回答這些問題嗎
思路
題目問的是區間[x,y]最大連續子段和tmax
如果用線段樹求解,那麼就需要維護以下資訊
我們可以利用分治的思想,將一個子段分為左右兩個最大連續子段和,lmax,rmax;
同時需要維護左右區間的sum;那麼根節點 u.lmax = max(u.lmax,左sum+右lmax),同理維護u.rmax
那麼任意區間的最大連續和就可以分為三種情況
一種是隻在左兒子的tmax,一種是在右兒子的tmax,還有一個就是橫跨左右兒子 即 左二子的rmax+右兒子的lmax;
void pushup(Node &u,Node &l,Node &r) { u.sum=l.sum+r.sum; u.lmax=max(l.lmax,l.sum+r.lmax); u.rmax=max(r.rmax,r.sum+l.rmax); u.tmax=max(max(l.tmax,r.tmax),r.lmax+l.rmax); }
求得最大值即可;
那麼線段樹只需要用到單點修改和區間查詢即可
程式碼
#include <iostream> #include <cstring> #include <algorithm> using namespace std; #define int long long const int N = 5e+5; int a[N]; struct Node { int l,r; int lmax,rmax,tmax,sum; }tre[N<<2]; void pushup(Node &u,Node &l,Node &r) { u.sum=l.sum+r.sum; u.lmax=max(l.lmax,l.sum+r.lmax); u.rmax=max(r.rmax,r.sum+l.rmax); u.tmax=max(max(l.tmax,r.tmax),r.lmax+l.rmax); } void pushup(int rt) { pushup(tre[rt],tre[rt*2],tre[rt*2+1]); } void build(int rt,int l,int r) { if(l == r) { tre[rt]={l,r,a[l],a[l],a[l],a[l]}; } else { tre[rt]={l,r}; int mid=(l+r)/2; build(rt*2,l,mid); build(rt*2+1,mid+1,r); pushup(rt); } } Node query(int rt,int l,int r) { if(tre[rt].l>=l&&tre[rt].r<=r) { return tre[rt]; } else { int mid = (tre[rt].l+tre[rt].r)/2; if(r<=mid) return query(rt*2,l,r); else if(l>mid) return query(rt*2+1,l,r); else { auto Left=query(rt*2,l,r); auto Right=query(rt*2+1,l,r); Node res; pushup(res,Left,Right); return res; } } } void modify(int rt,int x,int v) { if(tre[rt].l==x&&tre[rt].r==x) { tre[rt]={x,x,v,v,v,v}; } else { int mid = (tre[rt].l+tre[rt].r)/2; if(x<=mid) modify(rt*2,x,v); else modify(rt*2+1,x,v); pushup(rt); } } signed main() { int n,m; cin >> n >> m; for(int i=1;i<=n;i++) { cin >> a[i]; } build(1,1,n); while (m -- ) { int k,x,y; cin >> k >> x >> y; if(k == 1) { if(x>y) swap(x,y); Node ans = query(1,x,y); cout<<ans.tmax<<endl; } else { modify(1,x,y); } } return 0; }
246. 區間最大公約數
如果想要維護一個區間的gcd,並進行區間修改的操作很難,但如果根據gcd的這個性質
gcd(a,b)=gcd(a,b−a)
便可以用線段樹維護差分去做,區間修改就很容易了,只需要單點修改左右端點即可
重點是如何用線段樹利用差分資訊去求區間[l,r]的gcd
根據gcd(a,b,c)=gcd(a,b-a,c-b);
我們第一個需要求a是多少,那就是1-l的sum;於是線段樹需要維護一個區間sum資訊
第二個就是去維護一個區間的gcd資訊,去將gcd(b-a,c-b)求出來
void pushup(Node &u,Node &l,Node &r) { u.sum=l.sum+r.sum; u.d=gcd(l.d,r.d); }
程式碼
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 5e+5;
typedef long long ll;
ll a[N];
struct Node
{
int l,r;
ll sum,d;
}tre[N<<2];
ll gcd(ll a,ll b)
{
return b?gcd(b,a%b):a;
}
void pushup(Node &u,Node &l,Node &r)
{
u.sum=l.sum+r.sum;
u.d=gcd(l.d,r.d);
}
void pushup(int rt)
{
pushup(tre[rt],tre[rt*2],tre[rt*2+1]);
}
void build(int rt,int l,int r)
{
if(l==r)
{
tre[rt]={l,r,a[l]-a[l-1],a[l]-a[l-1]};
}
else
{
tre[rt]={l,r};
int mid=(l+r)/2;
build(rt*2,l,mid);
build(rt*2+1,mid+1,r);
pushup(rt);
}
}
void modify(int rt,int x,ll d)
{
if(tre[rt].l==x&&tre[rt].r==x)
{
ll b=tre[rt].sum+d;
tre[rt]={x,x,b,b};
}
else
{
int mid = (tre[rt].l+tre[rt].r)/2;
if( x <= mid)
modify(rt*2,x,d);
else
modify(rt*2+1,x,d);
pushup(rt);
}
}
Node query(int rt,int l,int r)
{
if(tre[rt].l>=l&&tre[rt].r<=r)
{
return tre[rt];
}
else
{
int mid=(tre[rt].l+tre[rt].r)/2;
if( r <= mid)
{
return query(rt*2,l,r);
}
else if(l > mid)
{
return query(rt*2+1,l,r);
}
else
{
auto left=query(rt*2,l,r);
auto right=query(rt*2+1,l,r);
Node res;
pushup(res,left,right);
return res;
}
}
}
int main()
{
int n,m;
cin >> n >> m;
for(int i=1;i<=n;i++)
cin>>a[i];
build(1,1,n);
while(m --)
{
char op[2];
cin>>op;
if(*op=='Q')
{ int l,r;
cin >> l >> r;
Node res={0,0,0,0};
Node ans = query(1,1,l);
if(l+1<=r)
res = query(1,l+1,r);
ll se=gcd(ans.sum,res.d);
cout<<abs(se)<<endl;
}
else
{
int l,r;
ll d;
cin >> l >> r >> d;
modify(1,l,d);
if(r+1<=n)
modify(1,r+1,-d);
}
}
}
貼廣告 HDU - 2795
單點修改+區間查詢,將1-h區間以w建樹,維護一個區間能貼廣告的最大值