皮卡丘的梦想2
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
思路:
直接二维树状数组在线查询会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");
}
}
}
}