[BZOJ1935][SHOI2007]Tree 园丁的烦恼(离线+动态维护树状数组)

题目描述

传送门

题解

离线+动态维护树状数组。
按说以前应该也接触过这样的思想,比如说简单的树状数组求逆序对,还有昨天写的阿狸的打字机应该也用过了这样的思想,但是刚看这道题的时候没有联系到一起,,
坐标范围很大,首先想到离散化,将一个坐标离散化,另一个保留。树状数组按照离散化的那个坐标来建。
之后将所有的坐标按照未离散的一维排序,声明+询问(声明的坐标直接排序,询问的两个坐标拆成4个,就是二维树状数组的思路),然后顺着操作。如果遇到声明的坐标,就将这个位置+1,如果遇到询问的直接求和。
你会发现这样处理的目的是在询问的时候保证之前有声明的坐标都已经加过了,保证的答案的正确,也是动态维护树状数组的精妙所在。
最后将答案汇总一下。

代码

#include
#include
#include
#include
using namespace std;

const int max_n=5e5+5;
const int max_q=max_n*5;

int n,m,tot,cnt,ANS;
int x[max_n],y[max_n],a[max_n],b[max_n],c[max_n],d[max_n];
int p[max_q];
struct hp{
    int x,y,id,f;
}q[max_q];
int C[max_n],ans[max_n][5];

inline int in(){
    int x=0; char ch=getchar();
    while (ch<'0'||ch>'9') ch=getchar();
    while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x;
}
inline int cmp(hp a,hp b){
    return a.xx||(a.x==b.x&&a.fint loc,int val){
    for (int i=loc;i<=n;i+=i&(-i))
      C[i]+=val;
}
inline int query(int loc){
    int ans=0;
    for (int i=loc;i>=1;i-=i&(-i))
      ans+=C[i];
    return ans;
}

int main(){
    n=in(); m=in();
    for (int i=1;i<=n;++i){
        x[i]=in()+1; y[i]=in()+1;
        p[++tot]=y[i];
    }
    for (int i=1;i<=m;++i){
        a[i]=in()+1; b[i]=in()+1; c[i]=in()+1; d[i]=in()+1;
        p[++tot]=b[i]; p[++tot]=d[i];
    }
    sort(p+1,p+tot+1);
    tot=unique(p+1,p+tot+1)-p-1;
    for (int i=1;i<=n;++i){
        y[i]=lower_bound(p+1,p+tot+1,y[i])-p;
        q[++cnt].x=x[i]; q[cnt].y=y[i];
    }
    for (int i=1;i<=m;++i){
        b[i]=lower_bound(p+1,p+tot+1,b[i])-p;
        d[i]=lower_bound(p+1,p+tot+1,d[i])-p;
        q[++cnt].x=a[i]-1; q[cnt].y=b[i]-1; q[cnt].id=i; q[cnt].f=1;
        q[++cnt].x=a[i]-1; q[cnt].y=d[i]; q[cnt].id=i; q[cnt].f=2;
        q[++cnt].x=c[i]; q[cnt].y=b[i]-1; q[cnt].id=i; q[cnt].f=3;
        q[++cnt].x=c[i]; q[cnt].y=d[i]; q[cnt].id=i; q[cnt].f=4;
    }
    sort(q+1,q+cnt+1,cmp);
    for (int i=1;i<=cnt;++i){
        if (!q[i].f) add(q[i].y,1);
        else ans[q[i].id][q[i].f]=query(q[i].y);
    }
    for (int i=1;i<=m;++i){
        ANS=ans[i][4]-ans[i][3]-ans[i][2]+ans[i][1];
        printf("%d\n",ANS);
    }
}

总结

数据范围不要再错了。。。
考试之前治手残。
再出脑残错误自断双手。

你可能感兴趣的:(题解,bit,省选)