【BZOJ4942】[Noi2017]整数

题目描述去uoj

题解:如果只有加法,那么直接暴力即可。。。(因为1的数量最多nlogn个)

先考虑加法,比较显然的做法就是将A二进制分解成log位,然后依次更新这log位,如果最高位依然有进位,那么找到最高位后面的第一个0,将中间的所有1变成0,那个0变成1。这个显然要用到线段树,但是复杂度是nlog2n的,肯定过不去。

于是我在考场上yy了一下,这log位是连续的,我们每次都要花费log的时间去修改一个岂不是很浪费?我们可以先在线段树上找到这段区间,然后在线段树上dfs下去,这样,时间复杂度就变成O(logn+那段区间在线段树上的大小)。因为一颗正常的线段树的大小就是4*n的,而这里的那段区间的大小是log的,所以我猜测复杂度应该是log*常数的。但是不会证,考完试旁边的大佬都十分怀疑我的复杂度,搞得我也非常怀疑,但是。。但是AC了。

正解貌似是O(nlog2n/32)的线段树+压位?听说考场上这么写的全被卡常了,体会到了wys的险恶用心~

回来重码了一发,交到uoj上TLE了,交到BZ上AC了(因为是均摊复杂度嘛~)。

欢迎大佬告诉我这个算法的真正复杂度~

#include <cstdio>
#include <cstring>
#include <iostream>
#define lson x<<1
#define rson x<<1|1
using namespace std;
const int N=30000040;
int n,A,B,nxt,f,len;
int s[N+1<<2],p[50];
void pushdown(int l,int r,int x)
{
if(!s[x]) s[lson]=s[rson]=0;
if(s[x]==r-l+1)
{
int mid=l+r>>1;
s[lson]=mid-l+1,s[rson]=r-mid;
}
}
void pushup(int x)
{
s[x]=s[lson]+s[rson];
}
void dfs(int l,int r,int x)
{
if(l==r)
{
s[x]+=p[l-B];
while(s[x]>1) p[l-B+1]++,s[x]-=2;
while(s[x]<0) p[l-B+1]--,s[x]+=2;
return ;
}
pushdown(l,r,x);
int mid=l+r>>1;
dfs(l,mid,lson),dfs(mid+1,r,rson);
pushup(x);
}
void updata(int l,int r,int x,int a,int b)
{
if(a<=l&&r<=b)
{
dfs(l,r,x);
return ;
}
pushdown(l,r,x);
int mid=l+r>>1;
if(a<=mid) updata(l,mid,lson,a,b);
if(b>mid) updata(mid+1,r,rson,a,b);
pushup(x);
}
void modify(int l,int r,int x,int a,int b,int c)
{
if(a>b) return ;
if(a<=l&&r<=b)
{
s[x]=(r-l+1)*c;
return ;
}
pushdown(l,r,x);
int mid=l+r>>1;
if(a<=mid) modify(l,mid,lson,a,b,c);
if(b>mid) modify(mid+1,r,rson,a,b,c);
pushup(x);
}
void nxt0(int l,int r,int x,int a)
{
if(r<a||nxt<=l||s[x]==r-l+1) return ;
if(l==r)
{
nxt=l;
return ;
}
int mid=l+r>>1;
pushdown(l,r,x);
nxt0(l,mid,lson,a),nxt0(mid+1,r,rson,a);
}
void nxt1(int l,int r,int x,int a)
{
if(r<a||nxt<=l||!s[x]) return ;
if(l==r)
{
nxt=l;
return ;
}
int mid=l+r>>1;
pushdown(l,r,x);
nxt1(l,mid,lson,a),nxt1(mid+1,r,rson,a);
}
int query(int l,int r,int x,int a)
{
if(l==r) return s[x];
pushdown(l,r,x);
int mid=l+r>>1;
if(a<=mid) return query(l,mid,lson,a);
return query(mid+1,r,rson,a);
}
int rd()
{
int ret=0,f=1; char gc=getchar();
while(gc<'0'||gc>'9') {if(gc=='-') f=-f; gc=getchar();}
while(gc>='0'&&gc<='9') ret=ret*10+gc-'0',gc=getchar();
return ret*f;
}
int main()
{
n=rd(),rd(),rd(),rd();
int i;
for(i=1;i<=n;i++)
{
if(rd()==1)
{
A=rd(),B=rd(),f=1,len=0;
if(!A) continue;
if(A<0) f=-1,A=-A;
while(A) p[len++]=(A&1)*f,A>>=1;
p[len++]=0,p[len]=0,updata(0,N,1,B,B+len-1);
if(p[len]>0)
{
nxt=1<<30,nxt0(0,N,1,B+len);
modify(0,N,1,B+len,nxt-1,0),modify(0,N,1,nxt,nxt,1);
}
if(p[len]<0)
{
nxt=1<<30,nxt1(0,N,1,B+len);
modify(0,N,1,B+len,nxt-1,1),modify(0,N,1,nxt,nxt,0);
}
}
else A=rd(),printf("%d\n",query(0,N,1,A));
}
return 0;
}
//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. iOS地图 -- 定位初使用
  2. CentOS 6.8_x64 Oracle 12C 安装
  3. python手记(39)
  4. JavaScript创建类的方式
  5. PHP基础示例:用正则表达式修改配置信息
  6. 【原】cookie小结
  7. 【坑】zsh和oh-my-zsh卸载后导致无法登陆
  8. [疑难杂症]__点击win10屏幕最上方的边界会莫名其妙打开Internet Explorer浏览器,不胜其烦(2次ps:已解决!!!).
  9. Vusial Studio连接不到源代码管理器Vss
  10. centos7安装Lnmp(Linux+Nginx+MySql+Php+phpMyAdmin+Apache)
  11. [转]RSReportServer 配置文件
  12. windows 下 MySql5.6主从复制
  13. [转]如何将文件夹式的项目源码导入Visual Studio
  14. 转 docker 部署 kafka
  15. golang 错误处理与异常
  16. EasyUI Pagination 分页分页布局定义 显示按钮布局
  17. code1214 线段覆盖
  18. IE11上登陆oracle OEM时报:“证书错误,导航已阻止”且无继续浏览此网站(不推荐)的错误
  19. android studio 中类似VS的代码折叠功能Region
  20. UML类图详解_关联关系_多对一

热门文章

  1. Oracle 表分区partition(http://love-flying-snow.iteye.com/blog/573303)
  2. NULL和唯一约束UNIQUE的对应关系
  3. luogu P1336 最佳课题选择
  4. 开始docker
  5. oracle查询、删除表中相同的数据
  6. mac xampp命令行调用mysql
  7. VS2010中打开VS2012项目的方法
  8. GEOS 使用的例子
  9. 【性能优化】——前端性能优化之DOM
  10. 2016.7.12 针对不同的数据库类型generatorConfig文件中的数据库配置