• SDUT3930


    皮卡丘的梦想2

    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 的百分号 “%”(不包括引号)。

    Sample 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

    Output

    Case 1:
    %
    50
    50
    20 50
    %
    %

    题目大意:
    输入一个t,表示有 t 组测试样例,对于每组测试样例,输入n和q,表示一共有n种化石和q个操作,再输入q行,每行有三个整数。一共有三种操作:

    1. 如果输入1,紧接着输入 2 个整数 a (1 <= a <= n), b (1 <= b <= 60),表示第 a 个小镇引入了第 b 种进化石
    2. 如果输入2,紧接着输入 2 个整数 a (1 <= a <= n), b (1 <= b <= 60),表示第 a 个小镇失去了全部第 b 种进化石
    3. 如果输入3,紧接着输入 2 个整数 l, r (1 <= l <= r <= n),表示他想询问从第 l 个到第 r 个小镇上可收集的进化石有哪几种,并依次输出化石,如果有0种,则输出 %

    解题思路:
    这道题是线段树和状态压缩的题,关于状态压缩:一共有60种化石,不太好存,所以我们可以用二进制去存储,一开始所有博物馆的化石一定都是0种,我们可以用01来表示该化石的状态,比如:从左到右,第1个二进制位为1,则说明有第1种化石,如果为0则表示没有该种类的化石,我们存的时候和统计的时候都是通过位运算实现的,但是树中的还是要用十进制整数去存,一共有60位,我们用long long 去存。统计种数的时候用一个数组去存,通过位运算来计算哪一位上有1,哪一位上是1则说明有编号为这一位的化石。AC代码:

    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    using ll = long long;
    const int _max=1e5+50;
    ll tree[4*_max];
    void bd(int node,int start,int end)//刚开始初始化都为0
    {
    	if(start==end)
    	{
    		tree[node]=0;
    		return;
    	}
    	int mid=(start+end)>>1;
    	bd(node*2,start,mid);
    	bd(node*2+1,mid+1,end);
    	tree[node]=(tree[node*2]|tree[node*2+1]);//通过或运算的性质来添加化石,因为只要有一个1就是1,而两者都是1是还是1.
    	return;
    }
    void update(int node,int start,int end,int idx,int val,int flag)
    {
    	if(start==end)
    	{
    		ll tmp=1ll<<(val-1);//flag标记来判断添加还是删除化石,-1是因为我们是从1开始左移的,一开始就默认是1了。
    		if(flag)
    		  tree[node]|=tmp;
    		else
    		  tree[node]&=(~tmp);//取反以后再与tmp去与,就能保证这一位上的是0,其他位是1.
    		return;
    	}
    	int mid=(start+end)>>1;
    	if(idx<=mid)
    	  update(node*2,start,mid,idx,val,flag);
    	else
    	  update(node*2+1,mid+1,end,idx,val,flag);
    	tree[node]=(tree[node*2]|tree[node*2+1]);
    }
    ll query(int node,int start,int end,int l,int r)
    {
    	if(l<=start&&r>=end)
    	  return tree[node];
    	int mid=(start+end)>>1;
    	ll ans=0;
    	if(l<=mid)
    	  ans|=query(node*2,start,mid,l,r);
    	if(r>mid)
    	  ans|=query(node*2+1,mid+1,end,l,r);
    	return ans;
    }
    int main()
    {
    	int t,k=1;
    	cin>>t;
    	while(t--)
    	{
    		int n,m;
    		cin>>n>>m;
    		printf("Case %d:
    ",k++);
    		bd(1,1,n);
    		while(m--)
    		{
    			int c,l,r;
    			  cin>>c>>l>>r;
    			if(c==1||c==2)
    			{
    				if(c==1)
    				  update(1,1,n,l,r,1);
    				else
    				  update(1,1,n,l,r,0);
    			}
    			else
    			{
    				ll ans=query(1,1,n,l,r);
    				int k=1,k1[65],k2=0;
    				for(int i=0;i<60;i++)
    				  if(ans&(1ll<<i))
    				    k1[k2++]=i+1;
    				sort(k1,k1+k2);
    				if(k2==0)
    				  cout<<'%'<<endl;
    				else
    				{
    					for(int i=0;i<k2-1;i++)//注意一下格式,我PE了一发
    					  cout<<k1[i]<<" ";
    					cout<<k1[k2-1]<<endl;  
    				}
    			}
    		}
    	}
    	//system("pause");
    	return 0;
    }
    
  • 相关阅读:
    【LeetCode】650. 只有两个键的键盘
    【LeetCode】70. 爬楼梯
    【LeetCode】746. 使用最小花费爬楼梯
    【LeetCode】198. 打家劫舍
    【LeetCode】53.最大子序和
    【LeetCode】1056-易混淆数
    【人工智能系列】python的Quepy库的学习
    【计划书】关于运营商的人工智能的想法
    【转】经典!python中使用xlrd、xlwt操作excel表格详解
    转]python 结巴分词(jieba)学习
  • 原文地址:https://www.cnblogs.com/Hayasaka/p/14294273.html
Copyright © 2020-2023  润新知