線段樹模板題(結構體&一維陣列)(區間最值,求和)
阿新 • • 發佈:2019-02-06
1099: [視訊]線段樹(元問題byscy)線性結構求極值和修改
時間限制: 1 Sec 記憶體限制: 128 MB
提交: 496 解決: 165
[提交][狀態][討論版]
題目描述
【題意】
給出N個數,兩種操作:
1、C x y:修改第x個數的值為y;
2、P x y:求第x到第y個的最大值,注:x未必比y小
【輸入格式】
第一行輸入N和M(0 < N< = 200000,0 < M < 5000),N表示有N個數,M表示有M個操作
下來N個數
然後是M個操作。
【輸出格式】
遇到P操作的時候,輸出結果。
【樣例輸入】
5 6
1 2 3 4 5
P 1 5
C 3 6
P 3 4
P 4 5
C 2 9
P 1 5
【樣例輸出】
5
6
5
9
#include<iostream>
#include<cstring>
using namespace std;
int a[210000];//員工一開始只負責表達自己的值
struct node{
int l,r,lc,rc,c;}tr[410000];
int len ;
void bt(int l,int r)//申請一個管理者,管理第l到第r個員工
{
len++;
int now=len;//now記錄當前管理者的編號
tr[now].l=l;
tr[now].r=r;
tr[now].lc=tr[now].rc=-1;//一開始當前now管理者的左右副總都沒有人,為-1
if (l==r) tr[now].c=a[l];l==r;//表示當前管理者只有一個人
else//如果管理的人大於1,就有權申請兩個副總經理幫忙管理人。
{
int mid=(l+r)/2;
tr[now].lc=len+1;bt(l,mid);
tr[now].rc=len+1;bt(mid+1,r);
tr[now].c=max(tr[tr[now].lc].c,tr[tr[now].rc].c);//詢問左右副總的管理範圍的特徵值
}
}
void change(int now ,int x,int k )//在當前now管理者,所管理的範圍內,把管理第x 個員工的管理者的值改為k
{
if (tr[now].l==tr[now].r) {tr[now].c=k;return ;}
int lc=tr[now].lc,rc=tr[now].rc;
int mid=(tr[now].l+tr[now].r)/2;
if (x<=mid) change(lc,x,k);
else if (mid+1<=x) change(rc,x,k);
tr[now].c=max(tr[lc].c,tr[rc].c);
}
int findmax(int now,int l,int r)
{
if (l==tr[now].l&&tr[now].r==r) return tr[now].c;
int lc=tr[now].lc,rc=tr[now].rc;
int mid=(tr[now].l+tr[now].r)/2;
if (r<=mid) return findmax(lc,l,r);
else if (mid+1<=l) return findmax(rc,l,r);
else
return max(findmax(lc,l,mid),findmax(rc,mid+1,r));
}
int main()
{
int n,m,x,y;
char s;
cin>>n>>m;
for (int i=1;i<=n;i++)
{
cin>>a[i];
}
len=0;//一開始,有0個管理者
bt(1,n);
for (int i=0;i<m;i++)
{
cin>>s>>x>>y;
if (s=='C')
{
change(1,x,y);
}
else
{
if (x>y) cout<<findmax(1,y,x)<<endl;
else cout<<findmax(1,x,y)<<endl;
}
}
return 0;
}
再給出一個使用一維陣列的演算法
#include <iostream>
using namespace std;
int maxnum[400005];
int a[200005];
void bt(int now ,int l,int r)
{
if (l==r) maxnum[now]=a[l];
else
{
int mid=(l+r)/2;
bt(now*2,l,mid);
bt(now*2+1,mid+1,r);
maxnum[now]=max(maxnum[now*2],maxnum[now*2+1]);
}
}
void change(int now,int l,int r,int x,int k)//更新a[x]=k;
{
int mid=(l+r)/2;
if (l==r) maxnum[now]=k;
else
{
if (x<=mid)
change(now*2,l,mid,x,k);
else
change(now*2+1,mid+1,r,x,k);
maxnum[now]=max(maxnum[2*now],maxnum[2*now+1]);
}
}
int findmax(int now ,int l,int r,int x,int y)
{
int mid=(l+r)/2;
int ans=-1;
if (x<=l&&r<=y) return maxnum[now];//當前節點完全包含在查詢區間內
if (x<=mid) ans=max(ans,findmax(now*2,l,mid,x,y));
if (mid<y) ans=max(ans,findmax(now*2+1,mid+1,r,x,y));
return ans;
}
int main()
{
int n,m;
char s;int x,y;
cin>>n>>m;
for (int i=1;i<=n;i++)
cin>>a[i];
bt(1,1,n);
for(int i=0;i<m;i++)
{
cin>>s>>x>>y;
if (s=='C')
change(1,1,n,x,y);
else
{
if (x<y) cout<<findmax(1,1,n,x,y)<<endl;
else cout<<findmax(1,1,n,y,x)<<endl;
}
}
return 0;
}
加上了求區間最小值,和求和的內容
#include<iostream>
using namespace std;
int num[20000];
int maxnum[40000];
int minnum[40000];
int sumnum[40000];
void bt(int now ,int l,int r)
{
if (l==r)
{
maxnum[now]=num[l];
minnum[now]=num[l];
sumnum[now]=num[l];
}
else
{
int mid=(l+r)/2;
bt(now*2,l,mid);
bt(now*2+1,mid+1,r);
maxnum[now]=max(maxnum[now*2],maxnum[now*2+1]);
minnum[now]=min(minnum[now*2],maxnum[now*2+1]);
sumnum[now]=sumnum[now*2]+sumnum[now*2+1];
}
}
void change(int now,int l,int r,int x,int k)//將a[x]更新為k
{
if (l==r)
{
maxnum[now]=k;
minnum[now]=k;
sumnum[now]=k;
}
else
{
int mid=(l+r)/2;
if (x<=mid) change(now*2,l,mid,x,k);
else change(now*2+1,mid+1,r,x,k);
maxnum[now]=max(maxnum[now*2],maxnum[now*2+1]);
minnum[now]=min(minnum[now*2],maxnum[now*2+1]);
sumnum[now]=sumnum[now*2]+sumnum[now*2+1];
}
}
int findmax(int now,int l,int r,int x,int y)
{
if (x<=l&&r<=y)
return maxnum[now];
else
{
int maxl=-1,maxr=-1;
int mid=(l+r)/2;
if(x<=mid)
maxl= findmax(now*2,l,mid,x,y);
if (mid<y)
maxr=findmax(now*2+1,mid+1,r,x,y);
return max(maxl,maxr);
}
}
int findmin(int now,int l,int r,int x,int y)
{
if (x<=l&&r<=y)
return minnum[now];
else
{
int mid=(l+r)/2;
int minl=1<<29,minr=1<<29;
if (x<=mid) minl=findmin(now*2,l,mid,x,y);
if (mid<y) minr=findmin(now*2+1,mid+1,r,x,y);
return min(minl,minr);
}
}
int findsum(int now,int l,int r,int x,int y)
{
if (x<=l&&r<=y) return sumnum[now];
else
{
int mid=(l+r)/2;
int suml=0,sumr=0;
if (x<=mid) suml=findsum(now*2,l,mid,x,y);
if (mid<y) sumr=findsum(now*2+1,mid+1,r,x,y);
return suml+sumr;
}
}
int main()
{
int n,m;
char s;
int x;
int y;
cin>>n>>m;
for (int i=1;i<=n;i++)
{
cin>>num[i];
}
bt(1,1,n);
for(int i=0;i<m;i++)
{
cin>>s>>x>>y;
if (s=='C')
{
change(1,1,n,x,y);
}
else
{
cout<<findmax(1,1,n,x,y)<<endl;
cout<<findmin(1,1,n,x,y)<<endl;
cout<<findsum(1,1,n,x,y)<<endl;
}
}
return 0;
}