离线线段树,和上次做的BC是一样样的题。
题目大意,给你一串n项有序数列,然后再给m次查询,要找到查询区间内满足小于所查询的值的数的个数。然后是非常典型的离线线段树题。把所有的输入都放在一起,然后进行排序,按照高度排序,然后再按照操作的情况排序。嗯……然后其实不大会算复杂度的说……NLOGN?
1A的~~~ hiahia 弥补了上一题久debug不过的——不爽……………………
#include <iostream>
#include <stdio.h>
#include <algorithm>
using namespace std;
#define maxn 100100
int sum;
int tree[maxn*5];
struct node
{
int l,r,z;
int id,op;
}bri[maxn*2];
int tot[maxn];
int cmp(node a,node b)
{
if(a.z!=b.z) return a.z<b.z;
if(a.op!=b.op) return a.op<b.op;
if(a.l!=b.l) return a.l<b.l;
return a.r<b.r;
}
void creat(int l,int r,int rt)
{
tree[rt]=0;
if(l==r) return;
int mid=(l+r)/2;
creat(l,mid,rt<<1);
creat(mid+1,r,rt<<1|1);
}
void update(int pos,int l,int r,int rt)
{
if(l==pos&&r==pos)
{
tree[rt]++;
return;
}
int mid=(l+r)/2;
if(pos<=mid) update(pos,l,mid,rt<<1);
else update(pos,mid+1,r,rt<<1|1);
tree[rt]=tree[rt<<1]+tree[rt<<1|1];
}
void query(int ll,int rr,int l,int r,int rt)
{
if(ll==l&&rr==r)
{
sum+=tree[rt];
return;
}
int mid=(l+r)/2;
if(rr<=mid) query(ll,rr,l,mid,rt<<1);
else if(ll>mid) query(ll,rr,mid+1,r,rt<<1|1);
else query(ll,mid,l,mid,rt<<1),query(mid+1,rr,mid+1,r,rt<<1|1);
}
int main()
{
int T,cas=0;
scanf("%d",&T);
while(T--)
{
int n,m;
int tmp=0;
scanf("%d%d",&n,&m);
int i,j,k;
for(i=0;i<n;i++)
{
scanf("%d",&j);
bri[i].l=bri[i].r=i;
bri[i].z=j;
if(tmp<bri[i].l) tmp=bri[i].l;
bri[i].op=1;
}
int l,r;
for(i=n;i<n+m;i++)
{
scanf("%d%d%d",&l,&r,&j);
bri[i].l=l;
bri[i].r=r;
bri[i].z=j;
if(tmp<bri[i].r) tmp=bri[i].r;
bri[i].op=2;
bri[i].id=i-n;
}
int cnt=n+m;
creat(0,tmp,1);
/* sort(z,z+cnt);
int tmp=unique(z,z+cnt)-z;
for(i=0;i<tmp;i++)
mp[z[i]]=i; */
sort(bri,bri+cnt,cmp);
// cout<<endl;for(i=0;i<cnt;i++) printf("%d %d %d *%d\n",bri[i].l,bri[i].r,bri[i].z,bri[i].op);cout<<endl;
for(i=0;i<cnt;i++)
{
if(bri[i].op==1) update(bri[i].l,0,tmp,1);
else
{
sum=0;
query(bri[i].l,bri[i].r,0,tmp,1);
tot[bri[i].id]=sum;
}
}
printf("Case %d:\n",++cas);
for(i=0;i<m;i++) printf("%d\n",tot[i]);
}
return 0;
}