hdu 5032 不易发觉的树状数组

http://acm.hdu.edu.cn/showproblem.php?pid=5032

给定一个1000x1000的点阵,m组询问,每次询问一个由(0,0)、(x,0)点一以及从原点出发的方向向量(a,b)构成的直角三角形包围的点的权值和。

先把1000x1000个点离线出极角关系,然后对m个询问按极角排序,不停add,遇到询问的极角就query一次前缀和

#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <string>
#include <queue>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
#define RD(x) scanf("%d",&x)
#define RD2(x,y) scanf("%d%d",&x,&y)
#define clr0(x) memset(x,0,sizeof(x))
typedef long long LL;
int A,B,m;
struct point{
    int x,y;
    LL ans;
    double p;
}s[1000005],sc[100005];
bool cmpp(point a,point b)
{
    return a.p < b.p;
}
bool cmpid(point a,point b)
{
    return a.y < b.y;
}
LL bit[1005];
void add(int x,LL v)
{
    for(int i = x;i <= 1000;i += (i&-i))
        bit[i] += v;
}
LL query(int x)
{
    LL ans = 0;
    for(int i = x;i >= 1;i -= (i&-i))
        ans += bit[i];
    return ans;
}
int main(){
    int _,cnt = 0,cas = 1,x,a,b;
    RD(_);
    for(int i = 1;i <= 1000;++i)
    for(int j = 1;j <= 1000;++j){
        s[cnt++] = (point){i,j,0,1.0*j/i};
    }
    sort(s,s+cnt,cmpp);
    while(_--){
        RD2(A,B);
        RD(m);
        for(int i = 0;i < m;++i){
            RD2(a,b);RD(x);
            sc[i] = (point){x,i,0,1.0*b/a};
        }
        sort(sc,sc+m,cmpp);
        clr0(bit);
        int now = 0;
        for(int i = 0;i < m;++i){
            while(s[now].p <= sc[i].p){
                add(s[now].x,(LL)(s[now].x + A)*(s[now].y + B));
                now++;
            }
            sc[i].ans = query(sc[i].x);
        }
        sort(sc,sc+m,cmpid);
        printf("Case #%d:\n",cas++);
        for(int i = 0;i < m;++i)
            //cout<<sc[i].ans<<endl;
            printf("%I64d\n",sc[i].ans);
     }
     return 0;
 }


你可能感兴趣的:(树状数组)