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;
}

至于莫队嘛。。下次一定(逃