2018多校联合训练2

http://acm.hdu.edu.cn/contests/contest_show.php?cid=803

打的惨不忍睹,就过了3题

 

1004:水题,直接输出Yes就过了, solved by lyy

#include <bits/stdc++.h>
using namespace std;
#define ll long long
int n;

int main()
{
    while (~scanf("%d",&n))
    {
        printf("Yes\n");
    }
    return 0;
}

 

1010:逆序对*min(x,y) ,队友一开始WA了4发,给了他模板都不肯抄,偷懒随便上网找了两个逆序对的模板恰巧都是错的,GG  finally solved by lyy

#include <bits/stdc++.h>
using namespace std;
#define ll long long
ll cnt;
int n;
int a[500005],t[500005];
int x,y;

void merge_sort(int *A,int x,int y,int *T)
{
    if (y-x>1)
    {
        int m=x+(y-x)/2;
        int p=x,q=m,i=x;
        merge_sort(A,x,m,T);
        merge_sort(A,m,y,T);
        while (p<m ||q<y)
        {
            if (q>=y || (p<m && A[p]<=A[q])) T[i++]=A[p++];
            else {T[i++]=A[q++];cnt+=(ll)m-p;}
        }
        for (i=x;i<y;i++) A[i]=T[i];
    }
}


int main()
{
    while (~scanf("%d%d%d",&n,&x,&y))
    {
        memset(a,0,sizeof(a));
        memset(t,0,sizeof(t));
        for (int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
        }
        cnt=0;
        merge_sort(a,1,n+1,t);
        printf("%lld\n",(ll)cnt*(ll)min(x,y));
    }
    return 0;
}

 

1007 维护两个线段数即可,第一个是进位,一开始存的是b_{i},维护区间最小值,每次区间减一,如果为0,就需要进位,对应第二个线段树更新;第二个存的是答案,最终输出答案即可,一开始以为会炸,在极端情况下有可能到O(n^2),但是直接AC了

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define maxn 100005
int b[100005];
int n,m;
namespace lyy
{
    //线段树模板
    ll sum[maxn<<2],add[maxn<<2];//sum求和,add为懒惰标记   
    int a[maxn];//存原数组数据下标[1,n]   
    
    
    //pushup函数更新节点信息 ,这里是求和  
    void pushup(int rt)
    {
        sum[rt]=sum[rt<<1]+sum[rt<<1|1];
    } 
     
    //Build函数建树   
    void build(int l,int r,int rt)
    { 
        if(l==r) //若到达叶节点
        {
            sum[rt]=a[l];//储存数组值   
            return;  
        }  
        int m=(l+r)>>1;  
        //左右递归   
        build(l,m,rt<<1);  
        build(m+1,r,rt<<1|1);  
        //更新信息   
        pushup(rt);  
    }  
    
    void update(int L,int c,int l,int r,int rt)
    { 
        if(l==r) //到叶节点,修改
        {
            sum[rt]+=c;  
            return;  
        }  
        int m=(l+r)>>1;  
        //根据条件判断往左子树调用还是往右   
        if (L<=m) update(L,c,l,m,rt<<1);  
        else update(L,c,m+1,r,rt<<1|1);  
        pushup(rt);//子节点更新了,所以本节点也需要更新信息   
    } 
    
    void pushdown(int rt,int ln,int rn)
    {  
        //ln,rn为左子树,右子树的数字数量。   
        if(add[rt])
        {
            //下推标记   
            add[rt<<1]+=add[rt];  
            add[rt<<1|1]+=add[rt];  
            //修改子节点的sum使之与对应的Add相对应   
            sum[rt<<1]+=add[rt]*ln;  
            sum[rt<<1|1]+=add[rt]*rn;  
            //清除本节点标记   
            add[rt]=0;  
        }  
    }
    
    void update(int L,int R,int c,int l,int r,int rt)
    {
        if(L<=l && r<=R)//如果本区间完全在操作区间[L,R]以内
        { 
            sum[rt]+=c*(r-l+1);//更新数字和,向上保持正确  
            add[rt]+=c;
            //增加Add标记,表示本区间的sum正确,子区间的sum仍需要根据Add的值来调整  
            return ;   
        }  
        int m=(l+r)>>1;  
        pushdown(rt,m-l+1,r-m);//下推标记  
        //这里判断左右子树跟[L,R]有无交集,有交集才递归   
        if (L<=m) update(L,R,c,l,m,rt<<1);  
        if (R>m) update(L,R,c,m+1,r,rt<<1|1);   
        pushup(rt);//更新本节点信息   
    }
    
    ll query(int L,int R,int l,int r,int rt)
    {
        if(L<=l && r<=R)//在区间内,直接返回
        {
            return sum[rt];  
        }  
        int m=(l+r)>>1;
        //下推标记,否则sum可能不正确
        pushdown(rt,m-l+1,r-m);
          
        //累计答案  
        ll ans=0;  
        if(L <= m) ans+=query(L,R,l,m,rt<<1);
        if(R >  m) ans+=query(L,R,m+1,r,rt<<1|1);
        return ans;
    }
}
  
int sum[maxn<<2],add[maxn<<2];//sum求和,add为懒惰标记   
int a[maxn];//存原数组数据下标[1,n]   


//pushup函数更新节点信息 ,这里是求和  
void pushup(int rt)
{
    sum[rt]=min(sum[rt<<1],sum[rt<<1|1]);
} 
 
//Build函数建树   
void build(int l,int r,int rt)
{ 
    if(l==r)
    {
        sum[rt]=a[l];  
        return;  
    }  
    int m=(l+r)>>1;   
    build(l,m,rt<<1);  
    build(m+1,r,rt<<1|1); 
    pushup(rt);  
}  

void pushdown(int rt)
{     
    if(add[rt])
    {
        add[rt<<1]+=add[rt];  
        add[rt<<1|1]+=add[rt];     
        sum[rt<<1]+=add[rt];  
        sum[rt<<1|1]+=add[rt];  
        add[rt]=0;  
    }  
}

void go(int l,int r,int rt)
{
    if (l==r)
    {
        //cout<<l<<endl;
        lyy::update(l,1,1,n,1);
        sum[rt]=a[l]+1;
        return;
    }
    
    int m=(l+r)>>1;
    pushdown(rt);
    if (l<=m && sum[rt<<1]==1) go(l,m,rt<<1);
    if (r>m && sum[rt<<1|1]==1) go(m+1,r,rt<<1|1);
    pushup(rt);
}

void update(int L,int R,int l,int r,int rt)
{
    if(L<=l && r<=R)
    {
        if (sum[rt]==1)
        {
            go(l,r,rt);
            sum[rt]-=1;
            add[rt]-=1;
        }
        else
        {
            sum[rt]-=1;
            add[rt]-=1;
        }
        return;
    }  
    int m=(l+r)>>1;  
    pushdown(rt);  
    if (L<=m) update(L,R,l,m,rt<<1);  
    if (R>m) update(L,R,m+1,r,rt<<1|1);   
    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;
    pushdown(rt);
     
    int ans=0;  
    if(L <= m) ans+=query(L,R,l,m,rt<<1);
    if(R >  m) ans+=query(L,R,m+1,r,rt<<1|1);
    return ans;
}

int main()
{
    while (~scanf("%d%d",&n,&m))
    {
        memset(lyy::a,0,sizeof(lyy::a));
        memset(lyy::add,0,sizeof(lyy::add));
        lyy::build(1,n,1);
        for (int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
        }
        build(1,n,1);
        memset(add,0,sizeof(add));
        for (int i=1;i<=m;i++)
        {
            char c[10];
            int x,y;
            scanf("%s%d%d",c,&x,&y);
            if (c[0]=='a') update(x,y,1,n,1);
            else printf("%d\n",lyy::query(x,y,1,n,1));
        }
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值