区间求和
Problem:1328
Time Limit:2000ms
Memory Limit:165535K
Description
有一个序列包含n个正整数,现在有m次询问,每次询问为:求(L,R)的区间中小于等于K的数的和?
Input
输入包含多组数据。每组数据,第一行为n,表示这个整数序列长为n(1<=n<=1e5)。第二行输入整数序列x1,x2,……,xn(1<=xi<=1e9)。第三行输入m(1<=m<=1e5)。接下来m行,每行输入L,R,K(1<=L<=R<=n,0<=K<=1e9)。
Output
每组数据首先输出“Case #x:”,x从1开始,然后m行输出每次询问的结果,具体格式请参考样例。
Sample Input
6 2 5 3 4 7 6 3 2 5 4 3 6 5 1 4 3
Sample Output
Case #1: 7 7 5
Hint
Source
CJJ
中文题。
思路:
一开始想这道题,想到了莫队。然后到后来调莫队的时候发现要想调对,几乎就是暴力了。果断弃题,根本没有往主席树上想。QAQ
如果是用主席树写的话,因为K在查询是未知的,无法确定小于等于K的值都在哪一棵树上,所以需要离线处理。我们把需要插入的数和询问的区间和K值都记录下来,并按照从小到大排序。如果遇到了数,我们就插入这个值,如果遇到了询问,我们就访问最近的那棵树,访问l到r区间。最后按照询问的顺序输出就行了。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=1e5+10;
struct data
{
int v,id,f,l,r;
}q[2*maxn];
bool cmp(data a,data b)
{
if(a.v!=b.v)
return a.v<b.v;
if(a.f!=b.f)
return a.f<b.f;
return a.id<b.id;
}
int root[maxn],cnt,a[maxn];
long long ans[maxn];
struct node
{
int l,r,ls,rs;
long long sum;
}tr[maxn*30];
int build(int l,int r)
{
int now=++cnt;
tr[now].l=l,tr[now].r=r;
tr[now].sum=0;
if(l==r) return now;
int mid=(l+r)/2;
tr[now].ls=build(l,mid);
tr[now].rs=build(mid+1,r);
return now;
}
int update(int pre,int pos,int c)
{
int now=++cnt;
tr[now]=tr[pre];
tr[now].sum+=(long long)c;
int l=tr[pre].l,r=tr[pre].r;
if(l==r) return now;
int mid=(l+r)/2;
if(pos<=mid) tr[now].ls=update(tr[pre].ls,pos,c);
else tr[now].rs=update(tr[pre].rs,pos,c);
return now;
}
long long query(int now,int x,int y)
{
long long ans=0;
if(now<=0) return 0;
int l=tr[now].l,r=tr[now].r;
if(x<=l&&r<=y)
return tr[now].sum;
int mid=(l+r)/2;
if(x<=mid) ans+=query(tr[now].ls,x,y);
if(y>mid) ans+=query(tr[now].rs,x,y);
return ans;
}
int main()
{
int n,cas=1,m;
while(~scanf("%d",&n))
{
memset(q,0,sizeof(q));
cnt=0;
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
q[i].id=i,q[i].v=a[i];
q[i].f=0;
}
scanf("%d",&m);
for(int i=n+1;i<=n+m;i++)
{
scanf("%d%d%d",&q[i].l,&q[i].r,&q[i].v);
q[i].f=1;
q[i].id=i-n;
}
sort(q+1,q+1+m+n,cmp);
root[0]=build(1,n);
int num=0;
for(int i=1;i<=n+m;i++)
{
if(q[i].f==0)
{
num++;
root[num]=update(root[num-1],q[i].id,q[i].v);
}
else
{
long long anss=query(root[num],q[i].l,q[i].r);
ans[q[i].id]=anss;
}
}
printf("Case #%d:\n",cas++);
for(int i=1;i<=m;i++)
{
printf("%lld\n",ans[i]);
}
}
return 0;
}