noi2017 T1 整数 ——线段树

loj.ac上有  题目传送门

不过我还是把题目搬过来吧

整数(integer)
【题目背景】
在人类智慧的山巅,有着一台字长为 1048576 位的超级计算机,著名理论计算机科 学家 P 博士正用它进行各种研究。不幸的是,这天台风切断了电力系统,超级计算机 无法工作,而 P 博士明天就要交实验结果了,只好求助于学过 OI 的你......
【题目描述】 P 博士将他的计算任务抽象为对一个整数的操作。

具体来说,有一个整数 x ,一开始为 0。 接下来有 n 个操作,每个操作都是以下两种类型中的一种:

? 1 a b :将 x 加上整数 a·2b,其中 a 为一个整数,b 为一个非负整数

? 2 k :询问 x 在用二进制表示时,位权为 2k 的位的值(即这一位上的 1 代表 2k )

保证在任何时候,x≥0。
【输入格式】 从标准输入读入数据。

输入的第一行包含四个正整数 n,t1,t2,t3,n 的含义见题目描述,t1,t2,t3 的具体含义 见子任务。

接下来 n 行,每行给出一个操作,具体格式和含义见题目描述。

同一行输入的相邻两个元素之间,用恰好一个空格隔开。
【输出格式】

输出到标准输出。

对于每个询问操作,输出一行,表示该询问的答案(000 或 111)。 对于加法操作,没有任何输出

样例输入 1

10 3 1 2

1 100 0

1 2333 0

1 -233 0

2 5

2 7

2 15

1 5 15

2 15

1 -1 12

2 15

【样例 1 输出】

0

1

0

1

0

【子任务】 在所有测试点中,

1 ≤ t1 ≤ 3,1 ≤ t2 ≤ 4,1 ≤ t3 ≤ 2。

不同的 t1,t2,t3 对应的特殊限制 如下:

? 对于 t1 = 1 的测试点,满足 a = 1

?对于 t1 = 2 的测试点,满足 |a|= 1

? 对于 t1 = 3 的测试点,满足 |a|≤109 ? 对于 t2 = 1 的测试点,满足 0≤b,k≤30

? 对于 t2 = 2 的测试点,满足 0≤b,k≤100

? 对于 t2 = 3 的测试点,满足 0≤b,k≤n

? 对于 t2 = 4 的测试点,满足 0≤b,k≤30n

? 对于 t3 = 1 的测试点,保证所有询问操作都在所有修改操作之后

? 对于 t3 = 2 的测试点,不保证询问操作和修改操作的先后顺序

这道题首先 a*2^b 这个东西呢按我的想法是把 a 拆成2的x次幂的和 然后+b

如果只有加法当然很好写 但是这道题 a 可能是负的

所以我开了两个数组 s1 s2 来存 s1 存的是正的 s2 存的是负的

注意存的时候进位 均摊复杂度只有o(1) 所以暴力进位就好了

然后问题就转换成了已知两个高精度数,问他们的差的某一位是什么

然后分类可得

我们记一个数为 1(0)x

1 (0)  表示询问的这一位的值(因为是二进制,所以不是1就是0)

x就是询问位后面那一串东西(一坨1 0 混合体)

考虑减法是否退位的时候呢

1. x>=y:
1x-1y=0(x-y)
1x-0y=1(x-y)
0x-1y=1(x-y)
0x-0y=0(x-y)
2. x<y:
1x-1y=1(x-y+2^k)
1x-0y=0(x-y+2^k)
0x-1y=0(x-y+2^k)
0x-0y=1(x-y+2^k)

举个例子吧

10-10=00
10-00=10
01-10=11
01-01=00

10-11=11
10-01=01
00-11=01
00-01=11

注 题目保证x始终大于等于0 所以s1总和也一定大于s2

这样分析之后呢 问题就转换成了从1-x(即询问位)-1这个区间里s1 s2 的大小关系

如果 s1>=s2

那么答案就是 s1^s2(^念做异或)

如果 s2<=s2

那么答案就是 s1==s2 (==念做同或)

那么 x 和 y 的比较 其实就是比较字典序 找到第一个不一样的地方 哪个是1 哪个就大 (这么很好证明我就不详细讲了) 注意这里讲的都是二进制

算了举个例子吧 如果x是1000 y是0111 那么x是不是一定大于y

所以我们可以采用线段树维护区间内s1 s2 的大小

当然我这里采用的是zkw线段树 (自带底层优化自然会比较快 而且修改也很好写)

毕竟三千万(3e7)个叶子结点 同时线段树中下标也就是二进制中 2的次数

操作自然就是 区间内单点修改,前缀查询

那么我们每次操作1拆完a加上b以及进位之后

我们要记录一波 修改到的最左位置到最右位置 进位自然也算修改

然后就在线段树上暴力修改顺便上传信息 复杂度是 o( r-l + log(n))

操作2 询问的时候我们就找到区间中靠右(也就是比较大的位置)的第一个不一样的地方然后判断一波就好了

到这里题目就完美解决了 修改(modify)以及 查找(find) 就看代码吧

注: find我的写法呢 是向上走时,如果x是右孩子且x的兄弟为1才向下走

实测跑得也蛮快的 23333

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define LL long long
using namespace std;
const int M=3e7+31,N=1<<25;
int read(){
    int ans=0,f=1,c=getchar();
    while(c<‘0‘||c>‘9‘){if(c==‘-‘) f=-1; c=getchar();}
    while(c>=‘0‘&&c<=‘9‘){ans=ans*10+(c-‘0‘); c=getchar();}
    return ans*f;
}
int s1[M],s2[M],cnt;
int l,r,a,b,n,k;
void prepare(int x){
    if(!x) return ;
    int v=x>0?x:-x,w[31];
    cnt=0;
    for(int i=30;i>=0;i--){
        int now=1<<i;
        if(now&v) v-=now,w[++cnt]=i;
        if(!v) break;
    }
    l=w[cnt]+b; r=w[1]+b;
    if(x>0)
    for(int i=1;i<=cnt;i++){
        int now=w[i]+b;
        while(s1[now]) s1[now++]=0,r=max(r,now);
        s1[now]=1;
    }
    else
    for(int i=1;i<=cnt;i++){
        int now=w[i]+b;
        while(s2[now]) s2[now++]=0,r=max(r,now);
        s2[now]=1;
    }
}
int tr[2*N],T,now;
void modify(){
    for(int i=l;i<=r;i++) tr[i+N]=s1[i]^s2[i];
    for(l=(l+N)>>1,r=(r+N)>>1;l;l>>=1,r>>=1)
    for(int i=l;i<=r;i++) tr[i]=tr[i<<1]|tr[i<<1^1];
}
int find(int k){
    for(k+=N;k;k>>=1) if(k&1&tr[k^1]){
        for(k^=1;k<N;k=k<<1^tr[k<<1^1]);
        return k-N;
    }
    return -1;
}
int main()
{
    n=read(); T=read(); T=read(); T=read();
    for(int i=1;i<=n;i++){
        k=read();
        if(k==1){
            a=read(); b=read();
            prepare(a);
            modify();
        }
        else{
            a=read();
            now=find(a);
            if(s1[now]>s2[now]||now==-1) printf("%d\n",s1[a]^s2[a]);
            else printf("%d\n",s1[a]==s2[a]);
        }
    }
    return 0;
}

时间: 2024-07-30 19:22:50

noi2017 T1 整数 ——线段树的相关文章

【noi2017】 整数 线段树or模拟

ORZYYB 题目大意:你需要维护一个有$3\times 10^7$个二进制位的数,有一种修改方式和一种询问方式 对这个数加上$a\times2^b$,其中$|a|≤10^9$,$b≤3\times 10^7$,保证需要维护的这个数始终非负 询问这个数第k个二进制位的值 总共有$10^6$次询问/修改操作 我们不难发现,如果只有加法操作的话,对任意一个位执行加法操作,均摊进位次数是1. 证明是显然的(我貌似之前在MC里面用红石电路模拟过二进制进位过程....) 也就是说暴力加暴力进位的复杂度是正

【BZOJ4942】[Noi2017]整数 线段树+DFS(卡过)

[BZOJ4942][Noi2017]整数 题目描述去uoj 题解:如果只有加法,那么直接暴力即可...(因为1的数量最多nlogn个) 先考虑加法,比较显然的做法就是将A二进制分解成log位,然后依次更新这log位,如果最高位依然有进位,那么找到最高位后面的第一个0,将中间的所有1变成0,那个0变成1.这个显然要用到线段树,但是复杂度是nlog2n的,肯定过不去. 于是我在考场上yy了一下,这log位是连续的,我们每次都要花费log的时间去修改一个岂不是很浪费?我们可以先在线段树上找到这段区间

[BZOJ4942][NOI2017]整数(线段树+压位)

CCF的题经常是对于一个不是非常高级的算法或数据结构挖掘性质进行优化. 松爷的题总是充满常数优化气息,这个题也确实是在常数上做文章. 首先如果全加的话是可以直接暴力的,因为可以证明对每一位来说是均摊$O(1)$的,将a二进制分解一次. 然后将暴力想下去之后容易发现,二进制加法如果进位,肯定是找到这一位之前第一个为0的位加一,然后这两位之间的所有位都变成0(就是模拟竖式加法),减法反之. 于是这个东西就是前驱查找和区间修改,应用线段树解决,$O(n\log^{2}n)$. 但是看到极其相近的数据范

NOIP2017整数 【线段树】

题目 题目背景 在人类智慧的山巅,有着一台字长为10485761048576 位(此数字与解题无关)的超级计算机,著名理论计算机科 学家P博士正用它进行各种研究.不幸的是,这天台风切断了电力系统,超级计算机 无法工作,而 P 博士明天就要交实验结果了,只好求助于学过OI的你. . . . . . 题目描述 P 博士将他的计算任务抽象为对一个整数的操作. 具体来说,有一个整数xx ,一开始为00 . 接下来有nn 个操作,每个操作都是以下两种类型中的一种: 1 a b:将xx 加上整数a\cdot

acwing 243. 一个简单的整数问题2 树状数组 线段树

地址 https://www.acwing.com/problem/content/description/244/ 给定一个长度为N的数列A,以及M条指令,每条指令可能是以下两种之一: 1.“C l r d”,表示把 A[l],A[l+1],…,A[r] 都加上 d. 2.“Q l r”,表示询问 数列中第 l~r 个数的和. 对于每个询问,输出一个整数表示答案. 输入格式 第一行两个整数N,M. 第二行N个整数A[i]. 接下来M行表示M条指令,每条指令的格式如题目描述所示. 输出格式 对于

BZOJ 2124等差子序列 线段树&amp;&amp;hash

[题目描述 Description] 给一个 1 到 N 的排列{Ai},询问是否存在 1<=p1<p2<p3<p4<p5<…<pLen<=N(Len>=3),使得 Ap1,Ap2,Ap3,…ApLen 是一个等差序列. [输入描述 Input Description] 输入的第一行包含一个整数 T,表示组数. 下接 T 组数据,每组第一行一个整数 N,每组第二行为一个 1 到 N 的排列, 数字两两之间用空格隔开. [输出描述 Output Desc

LA3938:&quot;Ray, Pass me the dishes!&quot;(线段树)

Description After doing Ray a great favor to collect sticks for Ray, Poor Neal becomes very hungry. In return for Neal's help, Ray makes a great dinner for Neal. When it is time for dinner, Ray arranges all the dishes he makes in a single line (actua

bzoj 3772 :精神污染 线段树+打标记 or 主席树

3772: 精神污染 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 315  Solved: 87[Submit][Status][Discuss] Description 兵库县位于日本列岛的中央位置,北临日本海,南面濑户内海直通太平洋,中央部位是森林和山地,与拥有关西机场的大阪府比邻而居,是关西地区面积最大的县,是集经济和文化于一体的一大地区,是日本西部门户,海陆空交通设施发达.濑户内海沿岸气候温暖,多晴天,有日本少见的贸易良港神户港所在的神户

hdu 5692 Snacks 线段树+dfs

Snacks Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 1295    Accepted Submission(s): 302 Problem Description 百度科技园内有n个零食机,零食机之间通过n−1条路相互连通.每个零食机都有一个值v,表示为小度熊提供零食的价值. 由于零食被频繁的消耗和补充,零食机的价值v会时常发