CC DEC.17 Chef And Easy Xor Queries 分块+懒标记
2017-12-12 16:57
316 查看
题意:长度为n的序列a,Q次操作,操作1:(i,x)将第a[i]变为x. 操作2:(i,k) 问有多少个前缀j(j<=r)其异或和为k.
n,Q<=1e5,a[i],x,k<=1e6.
暴力的话 每次单点修改a[i],都要修改pre[j](j>=i)的前缀和.每次查询都要查询每个pre[i](i<=r) O(n*Q).
现在对pre来分块.每块维护cnt[i][x]:该块pre值为x的有多少个.
修改一个a[i]->y.
对于每一块,每个x出现cnt次 则现在变为x^a[i]^y 出现cnt次
1<=x<=1e5,不能对块内元素一个一个更新次数 则对每块都加上一个标记val[i],表示该块内每个pre真实值为pre[j]^val[i].
非整块的点 直接修改它的pre值和cnt值即可.
对于查询 非整块直接查询 注意其真实值为pre[i]^val[pos[i]] O(N*sqrt(N)).
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=120000,M=350;
int n,Q,a
,op,p,r,k,x,pre
,val
,m,num,pos
;
int cnt[M][N*10];
void init()
{
m=(int)sqrt(n),num=n/m;
if(n%m)
num++;
for(int i=1;i<=n;i++)
pos[i]=(i-1)/m+1,val[i]=0;
for(int i=1;i<=num;i++)
for(int j=(i-1)*m+1;j<=n&&j<=i*m;j++)
cnt[i][pre[j]]++;
}
int main()
{
scanf("%d%d",&n,&Q);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]),pre[i]=pre[i-1]^a[i];
init();
while(Q--)
{
scanf("%d",&op);
if(op==1)
{
scanf("%d%d",&p,&x);
for(int i=p;i<=pos[p]*m;i++)
{
cnt[pos[p]][pre[i]]--;
cnt[pos[p]][pre[i]^a[p]^x]++;
pre[i]=pre[i]^a[p]^x;
}
for(int i=pos[p]+1;i<=num;i++)
val[i]=val[i]^a[p]^x;
a[p]=x;
}
else
{
scanf("%d%d",&r,&k);
//for(int i=1;i<=n;i++)
// cout<<i<<' '<<(pre[i]^val[pos[i]])<<endl;
int res=0;
for(int i=1;i<=pos[r]-1;i++)
res+=cnt[i][k^val[i]];
for(int i=(pos[r]-1)*m+1;i<=r;i++)
if((pre[i]^val[pos[i]])==k)
res++;
printf("%d\n",res);
}
}
return 0;
}
n,Q<=1e5,a[i],x,k<=1e6.
暴力的话 每次单点修改a[i],都要修改pre[j](j>=i)的前缀和.每次查询都要查询每个pre[i](i<=r) O(n*Q).
现在对pre来分块.每块维护cnt[i][x]:该块pre值为x的有多少个.
修改一个a[i]->y.
对于每一块,每个x出现cnt次 则现在变为x^a[i]^y 出现cnt次
1<=x<=1e5,不能对块内元素一个一个更新次数 则对每块都加上一个标记val[i],表示该块内每个pre真实值为pre[j]^val[i].
非整块的点 直接修改它的pre值和cnt值即可.
对于查询 非整块直接查询 注意其真实值为pre[i]^val[pos[i]] O(N*sqrt(N)).
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=120000,M=350;
int n,Q,a
,op,p,r,k,x,pre
,val
,m,num,pos
;
int cnt[M][N*10];
void init()
{
m=(int)sqrt(n),num=n/m;
if(n%m)
num++;
for(int i=1;i<=n;i++)
pos[i]=(i-1)/m+1,val[i]=0;
for(int i=1;i<=num;i++)
for(int j=(i-1)*m+1;j<=n&&j<=i*m;j++)
cnt[i][pre[j]]++;
}
int main()
{
scanf("%d%d",&n,&Q);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]),pre[i]=pre[i-1]^a[i];
init();
while(Q--)
{
scanf("%d",&op);
if(op==1)
{
scanf("%d%d",&p,&x);
for(int i=p;i<=pos[p]*m;i++)
{
cnt[pos[p]][pre[i]]--;
cnt[pos[p]][pre[i]^a[p]^x]++;
pre[i]=pre[i]^a[p]^x;
}
for(int i=pos[p]+1;i<=num;i++)
val[i]=val[i]^a[p]^x;
a[p]=x;
}
else
{
scanf("%d%d",&r,&k);
//for(int i=1;i<=n;i++)
// cout<<i<<' '<<(pre[i]^val[pos[i]])<<endl;
int res=0;
for(int i=1;i<=pos[r]-1;i++)
res+=cnt[i][k^val[i]];
for(int i=(pos[r]-1)*m+1;i<=r;i++)
if((pre[i]^val[pos[i]])==k)
res++;
printf("%d\n",res);
}
}
return 0;
}
相关文章推荐
- CF&&CC百套计划2 CodeChef December Challenge 2017 Chef And Easy Xor Queries
- codechef Xor Queries (可持久化字典树)
- 【CodeChef】Chef and Churu 分块+树状数组
- codechef Tree and Queries Solved
- CodeChef:Chef and Subarray Queries(线段树)
- CodeChef JUNE17 - Chef and Prime Queries
- Codeforces Round #340 (Div. 2) E. XOR and Favorite Number(分块 (java))
- 【XSY2111】Chef and Churus 分块 树状数组
- [CC-XXOR]Chef and Easy Problem
- Codechef Xor Queries(可持久化字典树)
- [CodeChef - GERALD07 ] Chef and Graph Queries
- CodeChef - FNCS Chef and Churu(分块)
- [CC-CHANOQ]Chef and odd queries
- codeforces XOR and Favorite Number (莫队分块)
- [CC]Chef and Graph Queries
- 【Codechef】【Chef and Graph Queries】Lct 可持久化线段树
- CodeChef Chef and Churu [分块]
- CodeChef "Chef and Churus" 分块+树状数组
- 【欧拉筛+主席树】CodeChef PRMQ Chef and Prime Queries
- 【codechef FNCS】【Chef and Churu】【分块】