线段树+树状数组

直接放题:

儿童节快乐
(happy.cpp)
【描述】
儿童节即将到来。在这一天,小朋友们会得到好多糖果。在MAX城市,人民发明了一种糖果自动管理系统(ACM系统),该系统能管理N堆糖果。系统只能执行两种操作。
  (1)I a b c(1≤a≤b≤N,0 < c≤100),ACM将在堆a至堆b之间(包含a和b)每堆糖果加c个。 //改段
  (2)C a b(1≤a≤b≤N),ACM将会选择a到b堆之间糖果数最多的那堆糖果送给一个小朋友。如果有两堆或两堆以上糖果数为最大值,选择那么编号小的那堆。 //求点
  给出一系列的操作,对于每个C操作,输出堆的糖果数。

【输入】
  有多组测试数据。
  每组测试数据的第一行为两个整数N,M(0< N,M≤10^5),N表示糖果堆的数目,M表示操作的次数。
  下来M行,每行为一个操作。
  输入当N=0并且M=0时结束,并且不做任何处理。
  初始时,所有堆糖果数目为0。
【输出】
  对于每个C操作,输出小朋友能得到的糖果的数目。
【样例输入】
5 4
I 1 5 1
C 2 3
I 2 2 4
C 2 3
0 0
【样例输出】
1
4

#include<cstdio>
#include<cstring>
const int N=100005;
int n,m;
struct qq
{
    int l,r;
    int s1,s2;
    int z,z1;//最大的值 最大是哪一个编号
    int lazy; 
}s[N*2];
int num;
void bt (int l,int r)
{
    num++;
    int a=num;
    s[a].l=l;s[a].r=r;
    s[a].s1=s[a].s2=-1;
    s[a].z=0;
    s[a].z1=l;
    s[a].lazy=0;
    if (l==r) return ;
    int mid=(l+r)/2;
    s[a].s1=num+1;bt(l,mid);
    s[a].s2=num+1;bt(mid+1,r);
    return ;
}
void add (int now,int l,int r,int c)
{
    //printf("%d %d z:%d lazy:%d\n",s[now].l,s[now].r,s[now].z,s[now].lazy);
    if (s[now].l==s[now].r)
    {
    //  printf("YES:%d %d\n",l,r);
        s[now].z+=c;
        return ;
    }
    if (s[now].l==l&&s[now].r==r)
    {
        s[now].lazy+=c;
        s[now].z+=c;
        return ;
    }
    int s1=s[now].s1,s2=s[now].s2;
    s[s1].lazy+=s[now].lazy;
    s[s1].z+=s[now].lazy;
    s[s2].lazy+=s[now].lazy;
    s[s2].z+=s[now].lazy;
    s[now].lazy=0;
    int mid=(s[now].l+s[now].r)/2;
    if (r<=mid) add(s1,l,r,c);
    else if (l>mid) add(s2,l,r,c);
    else
    {
        add(s1,l,mid,c);
        add(s2,mid+1,r,c);
    }
    if (s[s1].z>=s[s2].z)
    {
        s[now].z=s[s1].z;
        s[now].z1=s[s1].z1;
    }
    else
    {
        s[now].z=s[s2].z;
        s[now].z1=s[s2].z1;
    }
    return ;
}
int z,z1;
void find (int now,int l,int r)
{
    if (s[now].l==l&&s[now].r==r)
    {
        z=s[now].z;
        z1=s[now].z1;
        return ;
    }
    int s1=s[now].s1,s2=s[now].s2;
    s[s1].lazy+=s[now].lazy;
    s[s1].z+=s[now].lazy;
    s[s2].lazy+=s[now].lazy;
    s[s2].z+=s[now].lazy;
    s[now].lazy=0;
    int mid=(s[now].l+s[now].r)/2;
    if (r<=mid) find (s1,l,r);
    else if (l>mid) find (s2,l,r);
    else
    {
        find(s1,l,mid);
        int a=z,a1=z1;
        find(s2,mid+1,r);
        if (a>=z)
        {
            z=a;
            z1=a1;
        }
    }
    return ;
}
int main()
{
    freopen("happy.in","r",stdin);
    freopen("happy.out","w",stdout);
    while (scanf("%d%d",&n,&m))
    {
    if (n==0&&m==0) break;
    num=0;bt(1,n);
    for (int u=1;u<=m;u++)
    {
    //for (int u=1;u<=num;u++) printf("%d %d %d %d z:%d z1:%d lazy:%d\n",s[u].l,s[u].r,s[u].s1,s[u].s2,s[u].z,s[u].z1,s[u].lazy);
        char ss[5];
        scanf("%s",ss);
        if (ss[0]=='I') 
        {
            int a,b,c;
            scanf("%d%d%d",&a,&b,&c);
            add(1,a,b,c);
        }
        else 
        {
            int a,b;
            scanf("%d%d",&a,&b);
            find (1,a,b);
            printf("%d\n",z);
            /*for (int u=1;u<=num;u++) printf("%d %d %d %d z:%d z1:%d lazy:%d\n",s[u].l,s[u].r,s[u].s1,s[u].s2,s[u].z,s[u].z1,s[u].lazy);
            printf("\n");*/
            add(1,z1,z1,-z);
        }
    }
    }
    return 0;
}

//很不好意思我遇到了一个很懒的出题老师:-)

儿童节快乐2
(happy2.cpp)

【问题描述】
儿童节来了。在这一天,小朋友们会得到好多糖果。在MAX城市,人民更新新型的糖果自动管理系统(ACM2系统),该系统能管理N*N堆糖果。系统只能执行两种操作。
  (1)I a b c d e(1≤a≤c≤N,1≤b≤d≤N,0 < e≤100),ACM2将在矩阵【a,b】-【c,d】之间的每堆糖果加e个。
  (2)C a b c d(1≤a≤c≤N,1≤b≤d≤N),ACM2将会选择矩阵【a,b】-【c,d】之间糖果数最多的那堆糖果送给一个小朋友。如果有两堆或两堆以上糖果数为最大值,先按行再按列选择编号小的那堆。
给出一系列的操作,对于每个C操作,输出堆的糖果数。

【输入描述】
第一行为两个整数N,M(0< N,M≤2000),N*N表示糖果堆的数目,M表示操作的次数。
接下来M行,每行为一个操作。
初始时,所有堆糖果数目为0。

【输出描述】
对于每个C操作,输出小朋友能得到的糖果的数目。

【输入样例】
3 4
I 1 1 3 3 1
C 2 2 3 3
I 2 1 3 2 2
C 1 1 3 3

【输出样例】
1
3

升级版将一维改成了二维
不要被迷惑了
数据范围比较小。暴力比树状数组/线段树还要快。
所以在比赛时的无上真理:
能打暴力,就打暴力
暴力万岁!

如果有同学不服可以用树状数组做
我并不介意被打脸
我脸皮厚嘛:-)

//happy暴力 
#include<cstdio>
#include<cstdlib>
#include<cstring>

int n,m;
int p[2010][2010];

int main()
{
    freopen("happy2.in","r",stdin);
    freopen("happy2.out","w",stdout);
    scanf("%d %d",&n,&m);
    memset(p,0,sizeof(p));
    for (int i=1;i<=m;i++)
    {
        char op[10];
        int a,b,c,d,e;
        scanf("%s",op);
        if (op[0]=='I')
        {
            scanf("%d %d %d %d %d",&a,&b,&c,&d,&e);
            for (int x=a;x<=c;x++)
                for (int y=b;y<=d;y++)
                    p[x][y]+=e;
        }
        if (op[0]=='C')
        {
            scanf("%d %d %d %d",&a,&b,&c,&d);
            int xx=a,yy=b,max=0;
            for (int x=a;x<=c;x++)
                for (int y=b;y<=d;y++)
                {
                    if (p[x][y]>max) 
                    {
                        max=p[x][y];
                        xx=x;yy=y;
                    }
                }
            printf("%d\n",max);
            p[xx][yy]=0;
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值