ACM常用模板——数据结构——线段树

(一)单点更新
     
     
     
     
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1 | 1
using namespace std;
const int maxn=222222;
int Max[maxn<<2];
void PushUp(int rt)    //向上更新
{
    Max[rt]=max(Max[rt<<1],Max[rt<<1|1]);
}
void build(int l,int r,int rt)  // 建立线段树
{
    if(l==r)
    {
        scanf("%d",&Max[rt]);
        return ;
    }
    int m=(l+r)>>1;
    build(lson);
    build(rson);
    PushUp(rt);
}
void update(int p,int v,int l,int r,int rt)  //单点更新
{
    if(l==r)
    {
        Max[rt]=v;
        return ;
    }
    int m=(l+r)>>1;
    if(p<=m) update(p,v,lson);
    else update(p,v,rson);
    PushUp(rt);
}
int query(int L,int R,int l,int r,int rt)  // 区间最大值查询
{
    if(L<=l&&r<=R)
    {
        return Max[rt];
    }
    int m=(l+r)>>1;
    int ans=0;
    if(L<=m) ans=max(ans,query(L,R,lson));
    if(R>m) ans=max(ans,query(L,R,rson));
    return ans;
}
int main()
{
    int n,m;
    while(~scanf("%d%d",&n,&m))
    {
        build(1,n,1);
        for(int i=0;i<m;i++)
        {
            char c[15];
            int x,y;
            scanf("%s%d%d",c,&x,&y);
            if(c[0]=='Q') printf("%d\n",query(x,y,1,n,1));
            else update(x,y,1,n,1);
        }
    }
    return 0;
}


题目大意:给你n个数。这n个数是0~n-1的某个排列。现在叫你求这n个数的逆序数,以及循环左移后的逆序数的最小值。例如,给你0,3,2,1

叫你求,03,2,1的逆序数,3,2,1,0的逆序数,2,1,0,3的逆序数,1,0,3,2的逆序数 中最小的逆序数是什么。

      
      
      
      
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1 | 1
using namespace std;
const int maxn=5005;
int sum[maxn<<2],x[maxn];
void PushUp(int rt)
{
    sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
void build(int l,int r,int rt)
{
    sum[rt]=0;
    if(l==r) return ;
    int m=(l+r)>>1;
    build(lson);
    build(rson);
    PushUp(rt);
}
void update(int p,int l,int r,int rt)
{
    if(l==r)
    {
        sum[rt]++;
        return ;
    }
    int m=(l+r)>>1;
    if(p<=m) update(p,lson);
    else update(p,rson);
    PushUp(rt);
}
int query(int L,int R,int l,int r,int rt)
{
    if(L<=l&&r<=R)
    {
        return sum[rt];
    }
    int m=(l+r)>>1;
    int ans=0;
    if(L<=m) ans+=query(L,R,lson);
    if(R>m) ans+=query(L,R,rson);
    return ans;
}
int main()
{
    int n;
    while(~scanf("%d",&n))
    {
        build(0,n-1,1);
        int sum=0;
        for(int i=0;i<n;i++)
        {
            scanf("%d",&x[i]);
            sum+=query(x[i]+1,n-1,0,n-1,1);
            update(x[i],0,n-1,1);
        }
        int ans=sum;
        for(int i=0;i<n;i++)
        {
            sum+=n-1-x[i]-x[i];
            ans=min(ans,sum);
        }
        printf("%d\n",ans);
    }
    return 0;
}


(二)成段更新

update:成段增减 query:区间求和
       
       
       
       
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1 | 1
using namespace std;
const int maxn=100005;
LL add[maxn<<2],sum[maxn<<2];
void PushUp(int rt)
{
    sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
void PushDown(int rt,int m)
{
    if(add[rt])
    {
        add[rt<<1]+=add[rt];
        add[rt<<1|1]+=add[rt];
        sum[rt<<1]+=(m-(m>>1))*add[rt];
        sum[rt<<1|1]+=(m>>1)*add[rt];
        add[rt]=0;
    }
}
void build(int l,int r,int rt)
{
    add[rt]=0;
    if(l==r)
    {
        scanf("%lld",&sum[rt]);
        return ;
    }
    int m=(l+r)>>1;
    build(lson);
    build(rson);
    PushUp(rt);
}
void update(int L,int R,int x,int l,int r,int rt)
{
    if(L<=l&&r<=R)
    {
        sum[rt]+=(LL)((r-l+1)*x);
        add[rt]+=(LL)x;
        return ;
    }
    PushDown(rt,r-l+1);
    int m=(l+r)>>1;
    if(L<=m) update(L,R,x,lson);
    if(R>m) update(L,R,x,rson);
    PushUp(rt);
}
LL query(int L,int R,int l,int r,int rt)
{
    if(L<=l&&r<=R)
    {
        return sum[rt];
    }
    PushDown(rt,r-l+1);
    int m=(l+r)>>1;
    LL ans=0;
    if(L<=m) ans+=query(L,R,lson);
    if(R>m) ans+=query(L,R,rson);
    return ans;
}
int main()
{
    int n,m,x,y,v;
    char op[5];
    while(~scanf("%d%d",&n,&m))
    {
        build(1,n,1);
        for(int i=0;i<m;i++)
        {
            scanf("%s",op);
            if(op[0]=='Q') scanf("%d%d",&x,&y),printf("%lld\n",query(x,y,1,n,1));
            else scanf("%d%d%d",&x,&y,&v),update(x,y,v,1,n,1);
        }
    }
    return 0;
}

(三)区间合并
区间合并 单点更新
模型:给出一个序列,两种操作,单点更新值,以及查询区间的最长连续递增子序列长度
      
      
      
      
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1 | 1
using namespace std;
const int maxn=100005,inf=1<<29;
int lsum[maxn<<2],rsum[maxn<<2],msum[maxn<<2],ln[maxn<<2],rn[maxn<<2];
void PushUp(int rt,int m)//利用子节点信息更新父节点
{
lsum[rt]=lsum[rt<<1];//根节点从左边其的最长区间至少等于左儿子从左边起得最长区间
rsum[rt]=rsum[rt<<1|1];
msum[rt]=max(msum[rt<<1],msum[rt<<1|1]);
ln[rt]=ln[rt<<1];
rn[rt]=rn[rt<<1|1];
if(rn[rt<<1]<ln[rt<<1|1])//左儿子区间右端点比右儿子区间左端点小
{
if(lsum[rt]==m-(m>>1)) lsum[rt]+=lsum[rt<<1|1];
if(rsum[rt]==(m>>1)) rsum[rt]+=rsum[rt<<1];
msum[rt]=max(msum[rt],rsum[rt<<1]+lsum[rt<<1|1]);
}
}
void build(int l,int r,int rt)//建树
{
if(l==r)
{
scanf("%d",&ln[rt]);
//printf("[%d,%d] = %d\n",l,r,ln[rt]);
rn[rt]=ln[rt];
lsum[rt]=rsum[rt]=msum[rt]=1;
return ;
}
int m=(l+r)>>1;
build(lson);
build(rson);
PushUp(rt,r-l+1);
//printf("msum[%d,%d] = %d\n",l,r,msum[rt]);
}
void update(int p,int x,int l,int r,int rt)//单点更新
{
if(l==r)
{
lsum[rt]=rsum[rt]=msum[rt]=1;
ln[rt]=rn[rt]=x;
return ;
}
int m=(l+r)>>1;
if(p<=m) update(p,x,lson);
else update(p,x,rson);
PushUp(rt,r-l+1);
}
int Query(int L,int R,int l,int r,int rt)
{
//区间是叶子节点或都可用或都不可用直接返回
if(L<=l&&r<=R) return msum[rt];
//if(l==r||msum[rt]==0||msum[rt]==r-l+1) return msum[rt];
int ans=0;
int m=(l+r)>>1;
if(L<=m) ans=max(ans,Query(L,R,lson));
if(R>m) ans=max(ans,Query(L,R,rson));
if(rn[rt<<1]<ln[rt<<1|1]) ans=max(ans,min(rsum[rt<<1],m-L+1)+min(lsum[rt<<1|1],R-m));//不能越了区间[L,R]的界
//printf("msum[%d,%d] = %d ans=%d\n",l,r,msum[rt],ans);
return ans;
//return max(ans,rsum[rt<<1]+lsum[rt<<1|1]);
}
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
//srand(time(NULL));
int n,m,x,y,t;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
char op[5];
build(1,n,1);
for(int i=0;i<m;i++)
{
scanf("%s%d%d",op,&x,&y);
if(op[0]=='U') update(x+1,y,1,n,1);
else printf("%d\n",Query(x+1,y+1,1,n,1));
}
}
return 0;
}

你可能感兴趣的:(acm)