皮卡丘的梦想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 操作,在一行中按编号升序输出所有可收集的进化石。如果没有进化石可收集,则输出一个 MeiK 的百分号 "%"(不包括引号)。
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 % %
题意:
有n个村庄,有最多60种石头,有三种操作:a b c ,a==1时表示b村庄加入第c种石头;a==2时表示b村庄移去第c种石头;a==3表示询问b到c村庄共有几种石头,输出石头的种类,如果没有石头输出%;
输入t组数据
输入n,m
输入m行操作
代码:
//第一次见这种的线段树,做题还是太少了。 //显然要用线段树,最多有60种石头,可以把他压缩一下,每个叶子节点存他有的石头的状态,更新时不过就是个位运算, //然后就是个水题了。 #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; typedef long long ll; const int MAXN=400009; ll sum[MAXN]; void pushup(int rt){ sum[rt]=(sum[rt<<1]|sum[rt<<1|1]); } void build(int l,int r,int rt){ if(l==r){ sum[rt]=0; return; } int mid=(l+r)>>1; build(l,mid,rt<<1); build(mid+1,r,rt<<1|1); pushup(rt); } void update(int id,int f,int c,int l,int r,int rt){ if(l==r){ ll tmp=(1LL<<c); if(!(sum[rt]&tmp)&&f) sum[rt]|=tmp; else if((sum[rt]&tmp)&&!f) sum[rt]^=tmp; return; } int mid=(l+r)>>1; if(id<=mid) update(id,f,c,l,mid,rt<<1); else update(id,f,c,mid+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]; ll ans=0; int mid=(l+r)>>1; if(L<=mid) ans|=query(L,R,l,mid,rt<<1); if(R>mid) ans|=query(L,R,mid+1,r,rt<<1|1); return ans; } int main() { int t,n,m; scanf("%d",&t); for(int cas=1;cas<=t;cas++){ scanf("%d%d",&n,&m); int a,b,c; build(1,n,1); printf("Case %d: ",cas); for(int i=0;i<m;i++){ scanf("%d%d%d",&a,&b,&c); if(a==1){ update(b,1,c-1,1,n,1); } else if(a==2){ update(b,0,c-1,1,n,1); } else if(a==3){ ll tmp=query(b,c,1,n,1); int nu=0,cnt[64]; for(int i=0;i<60;i++){ if(tmp&(1LL<<i)) cnt[nu++]=i+1; } if(nu==0){ printf("%% "); continue; } sort(cnt,cnt+nu); for(int i=0;i<nu-1;i++) printf("%d ",cnt[i]); printf("%d ",cnt[nu-1]); } } } return 0; }