题目链接
思路:首先转换以下问题,我们可以设置两个数组L【i】和R【i】,L【i】表示比i的左边所能到达的最近的数,R【i】表示比i的右边所能到达的最近的数,于是问题就转化为了,对于一个查询【l,r】如果i存在贡献的话,i一定满足l<=i<=r并且L【i】<l&&R【i】>r,这个就是典型的偏序问题了。我们还是先固定一遍,我们把查询按右端点固定,然后存一个优先队列表示当前查询下合法的i的集合。
对于当前的查询【li,ri】来说,我们先把i小于等于ri点的先全部存队列,我们假设这些点全部都能产生贡献,然后再查看队列里那些元素不符合条件,把不符合的全部pop同时把他们之前update给还原。
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=1e6+100;
#define pi pair<int,int>
ll c[maxn],a[maxn],l[maxn],r[maxn],ans=0;
struct cxk{
int l,r,id;
}s[maxn];
int lowbit(int x) {return x&-x;}
bool cmp(const cxk &a,const cxk &b)
{
return a.r<b.r;
}
void update(int x,int v)
{
if(x==0) return ;
while(x<maxn) c[x]+=v,x+=lowbit(x);
}
ll query(int x)
{
ll res=0;
while(x>0) res+=c[x],x-=lowbit(x);
return res;
}
int main()
{
int n,m,q,u,v;
scanf("%d %d %d",&n,&m,&q);
for(int i=1;i<=n;++i) scanf("%lld",&a[i]),l[i]=0,r[i]=1e9;
for(int i=1;i<=m;++i)
{
scanf("%d %d",&u,&v);
if(v<u) l[u]=max(l[u],1LL*v);
else r[u]=min(r[u],1LL*v);
}
for(int i=1;i<=q;++i) scanf("%d %d",&s[i].l,&s[i].r),s[i].id=i;
sort(s+1,s+1+q,cmp);
int now=0;
priority_queue<pi, vector<pi>, greater<pi> >qq;
for(int i=1;i<=q;++i)
{
while(now+1<=s[i].r)//先假设全部合法
{
qq.push({r[now+1],now+1});
update(now+1,a[now+1]);
update(l[now+1],-a[now+1]);
now++;
}
while(!qq.empty()&&qq.top().first<=now)//把队列里不合法的剔除掉,然后把他们之前的更新给还原
{
pi x=qq.top();
qq.pop();
update(x.second,-a[x.second]);
update(l[x.second],a[x.second]);
}
ans^=s[i].id*(query(s[i].r)-query(s[i].l-1));
}
printf("%lld\n",ans);
}