主席树和cdq分治都可以,而且都是很入门的做法。
这道题主席树的写法要好写一些,但是如果带修改的话,就得用cdq分治了。
主席树代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
struct node
{
int l, r, x;
}val[maxn*40];
int tot, root[maxn], a[maxn];
struct que
{
int l, r, z;
}que[maxn];
vector<int>v;
int getid(int x){return lower_bound(v.begin(), v.end(), x)-v.begin()+1;}
void inser(int l, int r, int pre, int &now, int x)
{
now=++tot;
val[now]=val[pre];
val[now].x++;
if(l>=r)return;
int mid=(l+r)>>1;
if(x<=mid)inser(l, mid, val[pre].l, val[now].l, x);
else inser(mid+1, r, val[pre].r, val[now].r, x);
return;
}
int query(int l, int r, int rl, int rr, int L, int R)
{
if(L<=l && r<=R)
{
return val[rr].x-val[rl].x;
}
int mid=(l+r)>>1, res=0;
if(L<=mid)res+=query(l, mid, val[rl].l, val[rr].l, L, R);
if(mid<R)res+=query(mid+1, r, val[rl].r, val[rr].r, L, R);
return res;
}
int main()
{
int i, j, t, e=1, n, m, x, y, z;
cin>>t;
while(t--)
{
scanf("%d%d", &n, &m);
tot=0;
for(i=1; i<=n; i++)
{
scanf("%d", &a[i]);
v.push_back(a[i]);
}
printf("Case %d:\n", e++);
for(i=1; i<=m; i++)
{
scanf("%d%d%d", &que[i].l, &que[i].r, &que[i].z);
que[i].l, que[i].r++;
v.push_back(que[i].z);
}
sort(v.begin(), v.end());v.erase(unique(v.begin(), v.end()), v.end());
int len=v.size();
for(i=1; i<=n; i++)
{
a[i]=getid(a[i]);
inser(1, len, root[i-1], root[i], a[i]);
}
for(i=1; i<=m; i++)
{
printf("%d\n", query(1, len, root[que[i].l], root[que[i].r], 1, getid(que[i].z)));
}
for(i=0; i<=tot; i++)val[i].x=0;
}
return 0;
}
cdq代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn=2e5+5;
struct node
{
int pos;
int val;
int id;
int qid;
bool operator <(const node &a)const
{
if(pos!=a.pos)return pos<a.pos;
else return id<a.id;
}
}op[maxn], T[maxn];
int ord[maxn];
int bit[maxn];
int ans[maxn];
int lowbit(int x)
{
return x&-x;
}
void add(int x, int y)
{
while(x<maxn)
{
bit[x]+=y;
x+=lowbit(x);
}
}
int sum(int x)
{
int res=0;
while(x>0)
{
res+=bit[x];
x-=lowbit(x);
}
return res;
}
void cdq(int l, int r)
{
if(r-l<=1)return;
int mid=(l+r)>>1;
cdq(l, mid); cdq(mid, r);
int p=l, q=mid, o=0, siz=0;
while(p<mid && q<r)
{
if(op[p]<op[q])
{
if(op[p].id==0)
{
add(op[p].val, 1);
siz++;
}
T[o++]=op[p++];
}
else
{
if(op[q].id>0)
{
int s=op[q].id==1?-1:1;
ans[op[q].qid]+=s*(sum(op[q].val));
}
T[o++]=op[q++];
}
}
while(q<r)
{
if(op[q].id>0)
{
int s=op[q].id==1?-1:1;
ans[op[q].qid]+=s*(sum(op[q].val));
}
T[o++]=op[q++];
}
for(int i=l; i<p; i++)if(op[i].id==0)add(op[i].val, -1);
while(p<mid)
{
T[o++]=op[p++];
}
for(int i=l; i<r; i++)
{
op[i]=T[i-l];
}
return;
}
int main()
{
int t, i, e=1, j, q;
cin>>t;
while(t--)
{
int n, m;
scanf("%d%d", &n, &m);
for(i=0; i<=n+m; i++)ans[i]=0;
for(i=1; i<=n; i++)
{
scanf("%d", &op[i].val);
op[i].id=0;
op[i].pos=i;
ord[i]=op[i].val;
}
int j=i, x, y, z, q=0;
for(i=1; i<=m; i++)
{
scanf("%d%d%d", &x, &y, &z);
ord[n+i]=z;
op[j].id=1, op[j].pos=x, op[j].val=z, op[j].qid=q;
j++;
op[j].id=2, op[j].pos=y+1, op[j].val=z, op[j].qid=q;
q++, j++;
}
sort(ord+1, ord+n+m+1);
int len=unique(ord+1, ord+m+n+1)-ord, bound=j-1;
for(i=1; i<j; i++)
{
op[i].val=lower_bound(ord+1, ord+len, op[i].val)-ord;
}
cdq(1, j);
printf("Case %d:\n", e++);
for(i=0; i<q; i++)printf("%d\n", ans[i]);
}
return 0;
}