师创杯”山东理工大学第九届ACM程序设计竞赛(网络同步赛)--I皮卡丘的梦想2

作为水题王者前去水了一波山东理工大学的校赛,这道题一个小细节坑了我2个小时,思路其实很简单,就是线段树单点更新的模板,用一个60的数组标记,如果这个区间内有I种类的化石,那么就是1,否则为0,加入新化石的时候很容易想到,就是删除化石的时候,这个点删除了,但是如果这个区间的另外一个点有的话,那么这个区间还是要标记为1的,所以删除的时候要麻烦一点,最后,询问,用另外一个数组来保存这个区间的化石种类的有和无,需要注意的是,已经有了,赋值的时候就不需要把1的赋值取消(坑了两个小时),最后再输出就好了:

皮卡丘的梦想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
%
%
#include <iostream>
#include <stdio.h>
#include <string.h>
#define siz 100005
#define lson(x) ((x)<<1)
#define rson(x) (((x)<<1)|1)
using namespace std;
struct node{
    int is[65];
    int mx;
};
int p[siz];
node S[siz<<2];
int n,m;
void build(int root,int left,int right){
    if(left==right){
        memset(S[root].is,0,sizeof(S[root].is));
        return ;
    }
    int mid=(left+right)>>1;
    build(lson(root),left,mid);
    build(rson(root),mid+1,right);
    memset(S[root].is,0,sizeof(S[root].is));
}
void updata1(int root,int left,int right,int a,int b){
    if(left==right){
       // if(a==left)
        S[root].is[b]=0;
        return ;
    }
    int mid=(left+right)>>1;
    if(a<=mid){
        updata1(lson(root),left,mid,a,b);
    }else{
        updata1(rson(root),mid+1,right,a,b);
    }
    if(S[lson(root)].is[b]==1||S[rson(root)].is[b]==1){
        S[root].is[b]=1;
    }else{
        S[root].is[b]=0;
    }
}
void updata(int root,int left,int right,int a,int b){
    if(a>=left&&a<=right){
       // cout<<b<<endl;
            S[root].is[b]=1;
    }
    if(left==right){
        if(a==left){
            S[root].is[b]=1;
        }
        return ;
    }
    int mid=(left+right)>>1;
    if(a<=mid){
        updata(lson(root),left,mid,a,b);
    }else{
        updata(rson(root),mid+1,right,a,b);
    }
}
int ff[65];
void query(int root,int left,int right,int l,int r){
    if(left==l&&right==r){
        for(int i=1;i<=60;i++){
            if(ff[i]!=1)
            ff[i]=S[root].is[i];
        }
        return ;
    }
    int mid=(left+right)>>1;
   // cout<<mid<<" "<<l<<" "<<r<<endl;
    if(r<=mid){
        query(lson(root),left,mid,l,r);
    }
    else if(l>=mid+1){
        query(rson(root),mid+1,right,l,r);
    }
    else{
        query(lson(root),left,mid,l,mid);
        query(rson(root),mid+1,right,mid+1,r);
    }
}

void solve(){
    build(1,1,n);
    while(m--){
        memset(ff,0,sizeof(ff));
        int q,a,b;

        scanf("%d %d %d",&q,&a,&b);
        if(q==1){
            updata(1,1,n,a,b);
        }
        else if(q==2){
            updata1(1,1,n,a,b);
        }
        else{
            query(1,1,n,a,b);
            int flag=1;
            for(int i=1;i<=60;i++){
                if(ff[i]!=0){
                    if(flag){
                        printf("%d",i);
                        flag=0;
                    }
                    else
                    printf(" %d",i);
                }
            }
            if(flag){
                //puts("%");
                printf("%%\n");
            }
            else
            printf("\n");
        }
    }
}
int main()
{
    int t;

    scanf("%d",&t);
    for(int i=1;i<=t;i++){
        printf("Case %d:\n",i);
        scanf("%d%d",&n,&m);

        solve();
    }

    return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值