“师创杯”山东理工大学第九届ACM程序设计竞赛 正式赛 I.皮卡丘的梦想2【树状数组】水题

皮卡丘的梦想2

Time Limit: 1000MS  Memory Limit: 65536KB
Problem Description

一天,一只住在 501 的皮卡丘决定发奋学习,成为像 LeiQ 一样的巨巨,于是他向镇上的贤者金桔请教如何才能进化成一只雷丘。

金桔告诉他需要进化石才能进化,并给了他一个地图,地图上有 n 个小镇,他需要从这些小镇中收集进化石。

接下来他会进行 q 次操作,可能是打听进化石的信息,也可能是向你询问 l 到 r 之间的进化石种类。

如果是打听信息,则皮卡丘会得到一个小镇的进化石变化信息,可能是引入了新的进化石,也可能是失去了全部的某种进化石。

如果是向你询问,你需要回答他第 l 个小镇到第 r 个小镇之间的进化石种类。

Input

首先输入一个整数 T (1 <= T <= 10),代表有 T 组数据。

每组数据的第一行输入一个整数 n (1 <= n <= 100000) 和一个整数 q (1 <= q <= 100000),分别代表有 n 个小镇,表皮卡丘有 q 次操作。

接下来输入 q 行,对于每次操作,先输入操作类型:

1: 紧接着输入 2 个整数 a(1 <= a <= n), b(1 <= b <= 60),表示第 a 个小镇引入了第 b 种进化石。

2: 紧接着输入 2 个整数 a(1 <= a <= n), b(1 <= b <= 60),表示第 a 个小镇失去了全部第 b 种进化石。

3: 紧接着输入 2 个整数 l, r (1 <= l <= r <= n),表示他想询问从第 l 个到第 r 个小镇上可收集的进化石有哪几种。

Output

对于每组输入,首先输出一行 "Case T:",表示当前是第几组数据。

每组数据中,对于每次操作 3,按编号升序输出所有可收集的进化石。如果没有进化石可收集,则输出一个小豪的百分号 "%"(不要问我为什么,出题就是这么任性)。

Example Input
1
10 10
3 1 10
1 1 50
3 1 5
1 2 20
3 1 1
3 1 2
2 1 50
2 2 20
3 1 2
3 1 10
Example Output
Case 1:
%
50
50
20 50
%
%
Hint
Author
bLue

思路:


直接二维树状数组在线查询会TLE.

离线处理,分六十种物品分成六十次去暴力查询就行。


Ac代码:

#include<stdio.h>
#include<string.h>
using namespace std;
struct node
{
    int x,y,z;
}a[100505];
int tree[100505];
int ans[100505][62];
int n,q;
int lowbit(int x)//lowbit
{
    return x&(-x);
}
int getsum(int x)//求和求的是比当前数小的数字之和,至于这里如何实现,很简单:int sum=sum(a[i]);
{
    int sum=0;
    while(x>0)
    {
        sum+=tree[x];
        x-=lowbit(x);
    }
    return sum;
}
void add(int x,int c)//加数据。
{
    while(x<=n)
    {
        tree[x]+=c;
        x+=lowbit(x);
    }
}
int main()
{
    int t;
    int kase=0;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&q);
        memset(ans,0,sizeof(ans));
        for(int i=0;i<q;i++)scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z);
        for(int zhonglei=1;zhonglei<=60;zhonglei++)
        {
            memset(tree,0,sizeof(tree));
            for(int i=0;i<q;i++)
            {
                if(a[i].x==1)
                {
                    if(a[i].z==zhonglei)
                    {
                        add(a[i].y,1);
                    }
                }
                if(a[i].x==2)
                {
                    if(a[i].z==zhonglei)
                    {
                        int sum=getsum(a[i].y)-getsum(a[i].y-1);
                        add(a[i].y,-sum);
                    }
                }
                if(a[i].x==3)
                {
                    int sum=getsum(a[i].z)-getsum(a[i].y-1);
                    if(sum>0)
                    {
                        ans[i][zhonglei]=1;
                    }
                }
            }
        }
        printf("Case %d:\n",++kase);
        for(int i=0;i<q;i++)
        {
            if(a[i].x==3)
            {
                int flag=0;
                for(int j=1;j<=60;j++)
                {
                    if(ans[i][j]==1)
                    {
                        if(flag>0)printf(" ");
                        printf("%d",j);
                        flag++;
                    }
                }
                if(flag==0)printf("%%");
                printf("\n");
            }
        }
    }
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值