LOJ #2732. 「JOISC 2016 Day 2」雇佣计划 线段树

题意:给定一个数列,单点修改,求大于 $b_{i}$ 的极大连通块数目.  

有一个常见的套路:考虑 $i$ 与 $i-1$.  

当新加入 $i$ 时,$1$ ~ $a[i]$ 部分都新加入了一个连通块,然后我们发现我们多加了 $1$ ~ $min(a[i-1],a[i])$ 这一部分.  

那么这就对应了一个区间修改,单点查询,用线段树即可. 

code:  

#include <bits/stdc++.h>    
#define ll long long 
#define N 200006     
#define lson now<<1 
#define rson now<<1|1  
#define setIO(s) freopen(s".in","r",stdin) 
using namespace std; 
int n,m;        
int sum[N<<3],lazy[N<<3],a[N],A[N<<2];  
struct node
{
    int op,a,b;  
    node(int op=0,int a=0,int b=0):op(op),a(a),b(b){}  
}s[N<<2];  
void update(int l,int r,int now,int L,int R,int v) 
{   
    if(l>=L&&r<=R)  
    {
        lazy[now]+=v;   
        sum[now]+=(r-l+1)*v;   
        return;  
    }
    int mid=(l+r)>>1;    
    if(L<=mid)   
        update(l,mid,lson,L,R,v);  
    if(R>mid)  
        update(mid+1,r,rson,L,R,v);  
    sum[now]=sum[lson]+sum[rson]+(r-l+1)*lazy[now];   
}    
int query(int l,int r,int now,int L,int R) 
{
    if(l>=L&&r<=R)  
        return sum[now];  
    int mid=(l+r)>>1,re=(min(r,R)-max(l,L)+1)*lazy[now];   
    if(L<=mid)   
        re+=query(l,mid,lson,L,R);  
    if(R>mid)  
        re+=query(mid+1,r,rson,L,R);  
    return re;  
}   
int main() 
{ 
    //  setIO("input");  
    int i,j,tot=0;    
    scanf("%d%d",&n,&m);    
    for(i=1;i<=n;++i) 
        scanf("%d",&a[i]),A[++tot]=a[i];  
    for(i=1;i<=m;++i) 
    {
        scanf("%d",&s[i].op);   
        if(s[i].op==1)  
            scanf("%d",&s[i].b),A[++tot]=s[i].b;    
        else    
            scanf("%d%d",&s[i].a,&s[i].b),A[++tot]=s[i].b;   
    }  
    sort(A+1,A+1+tot);  
    for(i=1;i<=n;++i)  
        a[i]=lower_bound(A+1,A+1+tot,a[i])-A;  
    for(i=1;i<=m;++i)   
        s[i].b=lower_bound(A+1,A+1+tot,s[i].b)-A;    
    for(i=1;i<=n;++i) 
    {
        update(1,tot,1,1,a[i],1);            
        if(i>1) 
            update(1,tot,1,1,min(a[i],a[i-1]),-1);     
    }   
    for(i=1;i<=m;++i) 
    {
        if(s[i].op==1)
            printf("%d
",query(1,tot,1,s[i].b,s[i].b));    
        else 
        {  
            int cur=s[i].a;   
            update(1,tot,1,1,a[cur],-1);                
            if(cur>1)
            {
                update(1,tot,1,1,min(a[cur],a[cur-1]),1);        
            }
            if(cur<n)   
            { 
                update(1,tot,1,1,min(a[cur],a[cur+1]),1);              
            }
            a[cur]=s[i].b;   
            update(1,tot,1,1,a[cur],1);   
            if(cur>1)
                update(1,tot,1,1,min(a[cur],a[cur-1]),-1);        
            if(cur<n)   
                update(1,tot,1,1,min(a[cur],a[cur+1]),-1);   
        }
    }
    return 0;
}

  

原文地址:https://www.cnblogs.com/guangheli/p/12483571.html