【BZOJ】【2741】【FOTILE模拟赛】L
2015-06-04 21:25
441 查看
可持久化Trie+分块
神题……Orz zyf & lyd首先我们先将整个序列搞个前缀异或和,那么某一段的异或和,就变成了两个数的异或和,所以我们就将询问【某个区间中最大的区间异或和】改变成【某个区间中 max(两个数的异或和)】
要是我们能将所有[l,r]的答案都预处理出来,那么我们就可以O(1)回答了;然而我们并不能。
一个常见的折中方案:分块!
这里先假设我们实现了一个神奇的函数ask(l,r,x),可以帮我们求出[l,r]这个区间中的数,与x最大的异或值。
我们不预处理所有的左端点,我们只预处理$\sqrt{n}$个左端点,与$n$个右端点的答案。
也就是说:将序列分成$\sqrt{n}$块,b[i][j]表示在块 i 的左端到位置 j 这个区间中,选出两个数,其最大的Xor值。
对于询问[l,r]:设p是$l$后面第一个块的左端点,[p,r]的答案已经在b[p][r]中,[l,p]的答案就是对[l,p]中每个数x执行ask(l,r,x);
最后:ask(l,r,x)用可持久化Trie实现:具体来说就是,如果能往1走就往1走,如果1这棵子树中所有点都是出现在$l$之前的,那么就往0走。
可持久化Trie的写法……根据可持久化线段树的写法,yy一下试试?其实差不多= =
/************************************************************** Problem: 2741 User: Tunix Language: C++ Result: Accepted Time:6636 ms Memory:148948 kb ****************************************************************/ //BZOJ 2741 #include<cstdio> #include<cmath> #include<cstring> #include<cstdlib> #include<iostream> #include<algorithm> #define rep(i,n) for(int i=0;i<n;++i) #define F(i,j,n) for(int i=j;i<=n;++i) #define D(i,j,n) for(int i=j;i>=n;--i) #define pb push_back using namespace std; typedef long long LL; inline int getint(){ int r=1,v=0; char ch=getchar(); for(;!isdigit(ch);ch=getchar()) if (ch=='-') r=-1; for(; isdigit(ch);ch=getchar()) v=v*10-'0'+ch; return r*v; } const int N=150010,M=5e6+10; /*******************template********************/ int n,m,q,tot,rt ,id[M],t[M][2],a ,b[150] ; inline void Ins(int pre,int x,int k){ int now=rt[k]=++tot; id[tot]=k; D(i,30,0){ int j=(x>>i)&1; t[now][j^1]=t[pre][j^1]; t[now][j]=++tot; id[tot]=k; now=tot; pre=t[pre][j]; } } inline int ask(int l,int r,int x){ int ans=0,now=rt[r]; D(i,30,0){ int j=((x>>i)&1)^1; if (id[t[now][j]]>=l) ans|=1<<i; else j^=1; now=t[now][j]; } return ans; } int main(){ #ifndef ONLINE_JUDGE freopen("2741.in","r",stdin); freopen("2741.out","w",stdout); #endif n=getint(); q=getint(); F(i,1,n) a[i]=a[i-1]^getint(); id[0]=-1; Ins(rt[0],a[0],0); F(i,1,n) Ins(rt[i-1],a[i],i); int len=sqrt(n); m=n/len+(n%len!=0); rep(i,m) F(j,i*len+1,n) b[i][j]=max(b[i][j-1],ask(i*len,j-1,a[j])); int ans=0; F(i,1,q){ int x=((LL)ans+(LL)getint())%n+1,y=((LL)ans+(LL)getint())%n+1; if (x>y) swap(x,y); x--; int bx=x/len+(x%len!=0); ans=bx*len < y ? b[bx][y] : 0; F(j,x,min(bx*len,y)) ans=max(ans,ask(x,y,a[j])); printf("%d\n",ans); } return 0; }
View Code
2741: 【FOTILE模拟赛】L
Time Limit: 15 Sec Memory Limit: 162 MBSubmit: 1549 Solved: 413
[Submit][Status][Discuss]
Description
FOTILE得到了一个长为N的序列A,为了拯救地球,他希望知道某些区间内的最大的连续XOR和。即对于一个询问,你需要求出max(Ai xor Ai+1 xor Ai+2 ... xor Aj),其中l<=i<=j<=r。
为了体现在线操作,对于一个询问(x,y):
l = min ( ((x+lastans) mod N)+1 , ((y+lastans) mod N)+1 ).
r = max ( ((x+lastans) mod N)+1 , ((y+lastans) mod N)+1 ).
其中lastans是上次询问的答案,一开始为0。
Input
第一行两个整数N和M。第二行有N个正整数,其中第i个数为Ai,有多余空格。
后M行每行两个数x,y表示一对询问。
Output
共M行,第i行一个正整数表示第i个询问的结果。
Sample Input
3 31 4 3
0 1
0 1
4 3
Sample Output
57
7
HINT
HINTN=12000,M=6000,x,y,Ai在signed longint范围内。
Source
By seter[Submit][Status][Discuss]
相关文章推荐
- luabind 和设置1字节对齐导致服务器挂掉
- 结构体
- thinkPHP 无刷新分页
- 排序算法
- sgu251:Polymania(构造)
- Fibonacci的组合数通项公式
- 软件工程课程意见
- JavaScript读书笔记(3)-操作符、语句和函数
- dnspod的url转发
- spark中各种连接操作以及实用方法
- 移动端开发 根据html的字体大小来设置布局
- 使用Python扫描端口情况
- 图像基本噪声添加函数
- android设置图片自适应控件大小
- React 组件间通信
- 小组间的互评和自评
- 大数据架构:flume-ng+Kafka+Storm+HDFS 实时系统组合
- wordpress开启多站点 (Multisite)功能。
- hdn2050(递推之画直线求区域个数)
- content-type引发的CDN错误