wa/tle了三页才写出来。。。菜鸡果然是菜鸡
主席树
这个昨晚刚看的数据结构,敲的时候敲错了n多次。。
在树里,把数的版本号当作数组下标,树内记录每个区间内的数的出现次数,学过之后还是比较好理解的。
#include <iostream>
#include <cstdio>
using namespace std;
const int maxn=1e5+10;
struct node{
int l,r,sum;
}tree[maxn*40];
int cnt,root[maxn];
int n,m;
int a[maxn];
void insert(int l,int r,int pre,int &now,int val){
tree[++cnt]=tree[pre];
now=cnt;
tree[now].sum++;
if(l==r) return;
int m=(l+r)>>1;
if(val<=m) insert(l,m,tree[pre].l,tree[now].l,val);
else insert(m+1,r,tree[pre].r,tree[now].r,val);
}
int query(int l,int r,int L,int R,int k,int val){
if(r<=val) return tree[R].sum-tree[L].sum;
int m=(l+r)>>1;
if(val<=m) return query(l,m,tree[L].l,tree[R].l,k,val);
else if(k>m) return query(m+1,r,tree[L].r,tree[R].r,k,val);
else return query(l,m,tree[L].l,tree[R].l,k,m)+query(m+1,r,tree[L].r,tree[R].r,m+1,val);
}
int main()
{
scanf("%d %d",&n,&m);
int ss=0;
for(int i=1;i<=n;i++) scanf("%d",a+i),ss=max(a[i],ss);
for(int i=1;i<=n;i++){
insert(1,ss,root[i-1],root[i],a[i]);
}
while(m--){
int l,r,k;
scanf("%d %d %d",&l,&r,&k);
printf("%d\n",query(1,ss,root[l-1],root[r],1,k));
}
return 0;
}离线+树状数组
平时很少做离线做orz。我是看了邓老师的题解之后写的,做法是:分别对每次询问的k值和ai进行排序,然后在树状数组上标记下这个位置是否对答案有没有贡献。
比如说,按照样例:1 2 3 4 5
现在,要查询的k为3,那么,对答案有贡献的为止就是i=1,2,3,那么,就在树状数组内把1、2、3位置(所有ai<=k的位置)标记为1,然后用树状数组求前缀和就可以了。
真正起作用的是排序:我们把查询按照k值进行了排序,比如这次查询的是3,那就把所有数组中ai<=3的全部位置标记到树状数组中。下次要查询5的时候,上次我们标记了3的,我们就不需要再去标记ai<=3的部分了,直接标记ai==4、ai==5的部分就行了,因为ai被排序了,所以,我们可以通过记下上一次ai<=3的时候标记到了排序后的ai数组的那一个位置,然后,从那个位置继续标记就好了,是分块的思想。
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <vector>
#define lowbit(x) ((x)&-(x))
using namespace std;
const int maxn=1e5+10;
int tree[maxn];
int ans[maxn];
int n,m;
struct qs{
int l,r,k,num;
};
struct ai{
int pos,val;
friend bool operator<(const ai&x,const ai&y){
return x.val<y.val;
}
};
bool cmp(qs a,qs b){
return a.k<b.k;
}
vector<qs> ques;
vector<ai> as;
void modify(int x,int val){
while(x<=n){
tree[x]+=val;
x+=lowbit(x);
}
}
int query(int x){
int res=0;
while(x>0){
res+=tree[x];
x-=lowbit(x);
}
return res;
}
int main()
{
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++){
ai tmpp;
scanf("%d",&tmpp.val);
tmpp.pos=i;
as.push_back(tmpp);
}
for(int i=1;i<=m;i++){
int l,r,k;
scanf("%d %d %d",&l,&r,&k);
qs tmp={l,r,k,i};
ques.push_back(tmp);
}
sort(ques.begin(),ques.end(),cmp);
sort(as.begin(),as.end());
int pre=0;
int pree=0;
for(int i=0;i<ques.size();i++){
qs now=ques[i];
if(now.k!=pre)
{
while(as[pree].val<=now.k&&pree<as.size()){
modify(as[pree].pos,1);
pree++;
}
pre=now.k;
}
ans[now.num]=query(now.r)-query(now.l-1);
}
for(int i=1;i<=m;i++) printf("%d\n",ans[i]);
return 0;
}至于莫队嘛。。下次一定(逃

京公网安备 11010502036488号