传送门:https://cometoj.com/contest/58/problem/D
其实是个水题,不过我当场没有想起来先求一个总的,再用另一个树状数组维护另一个,减去多余的这种套路
我们预处理对于每一个点 a[i].id ,他在 [ a[i].ll , a[i].rr ]区间之内不会有可以直接到的点,那么我们按照a[i].ll排序
再对所有的询问的区间按照左端点排序。
对于每一个询问que[i], 他的答案其实是所有满足 que[i].l<=a[i].id<=que[i].r , a[i].l<=que[i].l, a[i].r >= que[i].r的这些菜地的a[i].w之和
维护两个树状数组,b1表示a[i].r为下标的a[i].w的前缀和,b2表示a[i].id为下标的a[i].r的前缀和
那么我们从左到右枚举询问,再设个a数组的,如果a[idx+1].l<=que[i].l 就加入,并更新b1,b2,记录一个decpos[i],表示a[i].id=i的有哪些下标,那么如果a[i].id<que[i].l,是不满足条件的,需要减去。
那么首先用b1算出那些 a[i].id>=que[i].l (前提已经保证),且a[i].rr>=que[i].r的 a[i].w之和,但是由于a[i].id需要<= que[i].r ,且哪些a[i].id>que[i].r 的,a[i].r>que[i].r,所以用b2算出a[i].id>que[i].r的多余的a[i].w和,从之前的总和中减去就是答案。
#include<bits/stdc++.h>
#define maxl 1000010
using namespace std;
int n,m,q;
long long b1[maxl],b2[maxl],ans[maxl];
struct node
{
int ll,rr;
int w,id;
bool operator < (const node &b)const
{
return id<b.id;
}
bool operator == (const node &b)const
{
return id==b.id;
}
}a[maxl];
vector <int> decpos[maxl];
struct qu
{
int l,r,id;
}que[maxl];
inline bool nodecmp(const node &x,const node &y)
{
if(x.ll==y.ll)
return x.id<y.id;
return x.ll<y.ll;
}
inline bool quecmp(const qu &x,const qu &y)
{
if(x.l==y.l)
return x.r<y.r;
return x.l<y.l;
}
inline void prework()
{
scanf("%d%d%d",&n,&m,&q);
for(int i=1;i<=n;i++)
{
a[i].id=i,a[i].ll=1;a[i].rr=n;
scanf("%d",&a[i].w);
}
int u,v;
for(int i=1;i<=m;i++)
{
scanf("%d%d",&u,&v);
if(v>u)
a[u].rr=min(a[u].rr,v-1);
if(v<u)
a[u].ll=max(a[u].ll,v+1);
}
sort(a+1,a+1+n,nodecmp);
for(int i=1;i<=q;i++)
{
scanf("%d%d",&que[i].l,&que[i].r);
que[i].id=i;
}
sort(que+1,que+1+q,quecmp);
}
inline void add(long long b[],int i,int x)
{
while(i<=n)
{
b[i]+=x;
i+=i&-i;
}
}
inline long long sum(long long b[],int i)
{
long long ret=0;
while(i)
{
ret+=b[i];
i-=i&-i;
}
return ret;
}
inline void mainwork()
{
int idx=0,l,x;
for(int i=1;i<=q;i++)
{
while(a[idx+1].ll<=que[i].l && idx<n)
{
++idx;
add(b1,a[idx].rr,a[idx].w);
add(b2,a[idx].id,a[idx].w);
decpos[a[idx].id].push_back(idx);
}
for(int j=que[i-1].l;j<=que[i].l-1;j++)
{
l=decpos[j].size();
for(int k=0;k<l;k++)
{
x=decpos[j][k];
add(b1,a[x].rr,-a[x].w);
add(b2,a[x].id,-a[x].w);
}
}
ans[que[i].id]=sum(b1,n)-sum(b1,que[i].r-1);
ans[que[i].id]-=sum(b2,n)-sum(b2,que[i].r);
}
}
inline void print()
{
long long x=0;
for(int i=1;i<=q;i++)
x^=i*ans[i];
printf("%lld\n",x);
}
int main()
{
prework();
mainwork();
print();
return 0;
}

本文介绍了一种使用树状数组解决区间查询问题的方法,通过预处理和维护两个树状数组,能够高效地计算满足特定条件的元素之和。这种方法适用于处理大量区间查询,特别是在元素范围较大时。
327

被折叠的 条评论
为什么被折叠?



