异或与区间加题解
异或与区间加题解
简要题意#
给定
10 10 3//n m K
2 0 3 0 1 0 0 2 1 2//a[i]
1 10 1//x y z
3 10 9
10 10 5
4 10 10
9 10 8
7 7 8
3 5 10
7 8 9
7 9 7
7 8 7
1 4 54 53 52 72 99 126 114 39
题解#
先来一个暴力的方法。首先容易想到对
#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int mod=1<<30;
int n,m,K,a[150010],sum[150010];
LL c[150010],cc[150010];
unordered_map<int,vector<int>>mp;
struct SYZ
{int x,y,z;}syz[150010];
inline int read()
{
int x=0,w=0;char ch=0;
while(!isdigit(ch)){w|=ch=='-';ch=getchar();}
while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return w?-x:x;
}
bool cmp(SYZ n1,SYZ n2)
{
if(n1.x^n2.x)return n1.x<n2.x;
return n1.y<n2.y;
}
void change(int x,int y)
{for(;x<=n;x+=x&-x)c[x]+=y;}
int ask(int x,int y=0)
{for(;x;x-=x&-x)y+=c[x];return y;}
int main()
{
n=read();m=read();K=read();
mp[0].push_back(0);
for(int i=1;i<=n;i++)
mp[sum[i]=sum[i-1]^(a[i]=read())].push_back(i);
for(int i=1;i<=m;i++){
int x=read(),y=read(),z=read();
syz[i]=(SYZ){x,y,z};
}
sort(syz+1,syz+1+m,cmp);
for(auto&x:mp)//x.first是键,x.second是值
reverse(x.second.begin(),x.second.end());
for(int i=1,j=1;i<=n;i++){//i是左端点
while(j<=m&&syz[j].x==i)
change(1,syz[j].z),change(syz[j].y+1,-syz[j].z),j++;
for(int x:mp[sum[i-1]^K]){//x是右端点
if(x<i)break;
int temp=ask(x);
cc[i]+=temp;
cc[x+1]-=temp;
}
}
for(int i=1;i<=n;i++)
printf("%lld%c",(cc[i]+=cc[i-1])%=mod," \n"[i==n]);
}
这里的
此方法的瓶颈在于:对于一个
我们可以在当
我们不妨对每一个这样的
设
我们要分别扫描所有的
我们不妨先考虑一个弱化版本,即:
显然,对于
#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int mod=1<<30;
int n,m,K,B,a[150010],sum[150010];
int sX[150010],sY[150010];
LL c[150010],cc[150010],prez[150010];
unordered_map<int,vector<int>>mp;
struct SYZ
{int x,y,z;}syz[150010];
inline int read()
{
int x=0,w=0;char ch=0;
while(!isdigit(ch)){w|=ch=='-';ch=getchar();}
while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return w?-x:x;
}
bool cmp(SYZ n1,SYZ n2)
{
if(n1.x^n2.x)return n1.x<n2.x;
return n1.y<n2.y;
}
void change(int x,int y)
{for(;x<=n;x+=x&-x)c[x]+=y;}
int ask(int x,int y=0)
{for(;x;x-=x&-x)y+=c[x];return y;}
void solve(int Y)//Y=sum[r]
{
int X=K^Y;//X=sum[l-1]
for(int i=1;i<=n;i++){
sX[i]=sX[i-1]+(sum[i-1]==X);
sY[i]=sY[i-1]+(sum[i]==Y);
}
for(int i=1;i<=n;i++)
if(sum[i-1]==X)
cc[i]+=prez[i]*(sY[n]-sY[i-1]);
LL temp=0;
for(int i=1;i<=n;i++){
if(sum[i-1]==X)temp+=prez[i];
if(sum[i]==Y)cc[i+1]-=temp;
}
}
int main()
{
n=read();m=read();K=read();B=sqrt(n);
mp[0].push_back(0);
for(int i=1;i<=n;i++)
mp[sum[i]=sum[i-1]^(a[i]=read())].push_back(i);
for(int i=1;i<=m;i++){
int x=read(),y=read(),z=read();
syz[i]=(SYZ){x,y,z};
prez[x]+=z;prez[y+1]-=z;
}
for(int i=1;i<=n;i++)
prez[i]+=prez[i-1];
sort(syz+1,syz+1+m,cmp);
for(auto&x:mp)//x.first是键,x.second是值
reverse(x.second.begin(),x.second.end());
for(int i=1,j=1;i<=n;i++){//i是左端点
while(j<=m&&syz[j].x==i)
change(1,syz[j].z),change(syz[j].y+1,-syz[j].z),j++;
if(mp[sum[i-1]^K].size()<B)
for(int x:mp[sum[i-1]^K]){//x是右端点
if(x<i)break;
int temp=ask(x);
cc[i]+=temp;
cc[x+1]-=temp;
}
}
for(auto&x:mp)
if(x.second.size()>=B)
solve(x.first);
for(int i=1;i<=n;i++)
printf("%lld%c",(cc[i]+=cc[i-1])%=mod," \n"[i==n]);
}
现在我们考虑怎么样拆分一个三元组,以及如何处理错误统计的
对于
在处理
#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int mod=1<<30;
int n,m,K,B,a[150010],sum[150010];
int sX[150010],sY[150010];
LL c[150010],cc[150010],prez[150010];
unordered_map<int,vector<int>>mp;
struct SYZ
{int x,y,z;}syz[150010];
inline int read()
{
int x=0,w=0;char ch=0;
while(!isdigit(ch)){w|=ch=='-';ch=getchar();}
while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return w?-x:x;
}
bool cmp(SYZ n1,SYZ n2)
{
if(n1.x^n2.x)return n1.x<n2.x;
return n1.y<n2.y;
}
void change(int x,int y)
{for(;x<=n;x+=x&-x)c[x]+=y;}
int ask(int x,int y=0)
{for(;x;x-=x&-x)y+=c[x];return y;}
void solve(int Y)//Y=sum[r]
{
int X=K^Y;//X=sum[l-1]
for(int i=1;i<=n;i++){
sX[i]=sX[i-1]+(sum[i-1]==X);
sY[i]=sY[i-1]+(sum[i]==Y);
}
memset(c,0,sizeof c);
for(int i=1;i<=m;i++){
int x=syz[i].x,y=syz[i].y,z=syz[i].z;
c[x]+=1ll*z*(sY[n]-sY[y]);
c[y+1]-=1ll*z*(sY[n]-sY[y]);
}
for(int i=1;i<=n;i++){
c[i]+=c[i-1];
if(sum[i-1]==X)
cc[i]+=prez[i]*(sY[n]-sY[i-1])-c[i];
}
memset(c,0,sizeof c);
for(int i=1;i<=m;i++){
int x=syz[i].x,y=syz[i].y,z=syz[i].z;
c[y+1]+=1ll*z*(sX[y]-sX[x-1]);
}
LL temp=0;
for(int i=1;i<=n;i++){
c[i]+=c[i-1];
if(sum[i-1]==X)temp+=prez[i];
if(sum[i]==Y)
cc[i+1]-=temp-c[i];
}
}
int main()
{
n=read();m=read();K=read();B=sqrt(n);
mp[0].push_back(0);
for(int i=1;i<=n;i++)
mp[sum[i]=sum[i-1]^(a[i]=read())].push_back(i);
for(int i=1;i<=m;i++){
int x=read(),y=read(),z=read();
syz[i]=(SYZ){x,y,z};
prez[x]+=z;prez[y+1]-=z;
}
for(int i=1;i<=n;i++)
prez[i]+=prez[i-1];
sort(syz+1,syz+1+m,cmp);
for(auto&x:mp)//x.first是键,x.second是值
reverse(x.second.begin(),x.second.end());
for(int i=1,j=1;i<=n;i++){//i是左端点
while(j<=m&&syz[j].x==i)
change(1,syz[j].z),change(syz[j].y+1,-syz[j].z),j++;
if(mp[sum[i-1]^K].size()<B)
for(int x:mp[sum[i-1]^K]){//x是右端点
if(x<i)break;
int temp=ask(x);
cc[i]+=temp;
cc[x+1]-=temp;
}
}
for(auto&x:mp)
if(x.second.size()>=B)
solve(x.first);
for(int i=1;i<=n;i++)
printf("%lld%c",(cc[i]+=cc[i-1])%=mod," \n"[i==n]);
}
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 清华大学推出第四讲使用 DeepSeek + DeepResearch 让科研像聊天一样简单!
· 实操Deepseek接入个人知识库
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库