2017 山理校赛 线段树单点更新+状压

本文介绍了一只立志成为雷丘的皮卡丘通过收集不同小镇的进化石来实现梦想的过程。采用数据结构与算法解决收集过程中遇到的问题,如进化石的引入与丢失等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

皮卡丘的梦想2
Time Limit: 1000MS Memory Limit: 65536KB
Submit Statistic
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
%
%

其实不用状压也能过 我用的状压

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=100000;
struct node
{
    ll num,fg;
}tree[maxn<<4];


void pushup(int id)  
{  
    tree[id].num=tree[id<<1].num|tree[id<<1|1].num;  
}  

// void pushdown(int id)  
// {  
//     if(tree[id].fg)  
//     {  
//         tree[id<<1].num=tree[id<<1|1].num=(1ll<<tree[id].fg);  
//         tree[id<<1].fg=tree[id<<1|1].fg=tree[id].fg;  
//         tree[id].fg=0;  
//     }  
// }  
// void build(int x,int l,int r)
// {
//     tree[x].fg=0;
//     if(l==r)
//     {
//         tree[x].num=(1LL<<val[l]);
//         return ;
//     }
//     int mid=(r+l)>>1;
//     build(x<<1,l,mid);
//     build(x<<1|1,mid+1,r);
//     pushup(x);
// }

void update(int rt,int l,int r,int b,ll co,int flag)
{
    if(l==r)
    {
        if(b==l)
        {
        if(flag)
        tree[rt].num|=(1LL<<co);
        else 
        tree[rt].num&=~(1LL<<co);
        }
        return;
    }
    // pushdown(rt);
    int mid=(l+r)>>1;
    if(b<=mid) update(rt<<1,l,mid,b,co,flag);
    if(b>mid) update(rt<<1|1,mid+1,r,b,co,flag);
    pushup(rt);
}

ll ans=0;
void query(int rt,int l,int r,int L,int R)
{
    if(L<=l&&r<=R)
    {
        ans|=tree[rt].num;
        return ;
    }
    // pushdown(rt);
    int mid=(l+r)>>1;
    if(L<=mid) query(rt<<1,l,mid,L,R);
    if(R>mid) query(rt<<1|1,mid+1,r,L,R);
}


int main()
{
    int t;
    scanf("%d",&t);
    for(int cc=1;cc<=t;cc++)
    {
        memset(tree,0,sizeof(tree));
        printf("Case %d:\n",cc );
        int n,m;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++)
        {
            int a,b,c;
            scanf("%d%d%d",&a,&b,&c);
            if(a==1)
            {
                update(1,1,n,b,c,1);
            }
            if(a==2)
            {
                update(1,1,n,b,c,0);
            }
            if(a==3)
            {
                ans=0;
                query(1,1,n,b,c);
                if(ans==0)
                {
                    printf("%\n");
                    continue;
                }
                int t=0;
                for(int i=1;i<=63;i++)
                {

                    if(ans&(1LL<<i))
                    {
                        if(t)
                        printf(" ");
                        t++;
                        printf("%d",i);
                    }
                }
                printf("\n");
            }
        }
    }
}

/***************************************************
User name: 青大机器人
Result: Accepted
Take time: 600ms
Take Memory: 2716KB
Submit time: 2017-06-04 20:57:38
****************************************************/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值