码迷,mamicode.com
首页 > 其他好文 > 详细

[hdu 5032]2014北京网络赛Always Cook Mushroom 离散化+离线线段树/树状数组

时间:2014-09-24 14:02:46      阅读:235      评论:0      收藏:0      [点我收藏+]

标签:线段树

Always Cook Mushroom

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 196    Accepted Submission(s): 54


Problem Description
Matt has a company, Always Cook Mushroom (ACM), which produces high-quality mushrooms. 

ACM has a large field to grow their mushrooms. The field can be considered as a 1000 * 1000 grid where mushrooms are grown in grid points numbered from (1, 1) to (1000, 1000). Because of humidity and sunshine, the productions in different grid points are not the same. Further, the production in the grid points (x, y) is (x + A)(y + B) where A, B are two constant. 

Matt,the owner of ACM has some queries where he wants to know the sum of the productions in a given scope(include the mushroom growing on the boundary). In each query, the scope Matt asks is a right angled triangle whose apexes are (0, 0), (p, 0), (p, q) 1<=p, q<=1000. 

As the employee of ACM, can you answer Matt’s queries?
 

Input
The first line contains one integer T, indicating the number of test cases.

For each test case, the first line contains two integers:A, B(0<=A, B<=1000).

The second line contains one integer M(1<=M<=10^5), denoting the number of queries.

In the following M lines, the i-th line contains three integers a, b, x (1<=a, b<=10^6, 1<=x<=1000), denoting one apex of the given right angled triangle is (x, 0) and the slope of its base is (a, b). It is guaranteed that the gird points in the given right angled triangle are all in valid area, numbered from (1, 1) to (1000, 1000).
 

Output
For each test case, output M + 1 lines.

The first line contains "Case #x:", where x is the case number (starting from 1) 

In the following M lines, the i-th line contains one integer, denoting the answer of the i-th query.
 

Sample Input
2 0 0 3 3 5 8 2 4 7 1 2 3 1 2 3 3 5 8 2 4 7 1 2 3
 

Sample Output
Case #1: 1842 1708 86 Case #2: 2901 2688 200
 

Source
 


题目大意

给定一片蘑菇田,只有从(1,1)至(1000,1000)的整数点能产蘑菇,点(x,y)的蘑菇产量为(x+A)(y+B)

给定直角三角形的两个顶点和斜边的斜率,用(a,b)的形式给出,求该三角形内的蘑菇产量和。


解题思路

因为点最多有1000*1000=100W个,可以先求出他们斜率并排序,找到每个斜率的rank,并将询问按照x排序,将斜率离散化,从上到下,从左到右将每个点加入线段树。询问实际上就是求一个前缀和了。一边处理询问,一边处理这些点。

每次区间更新该斜率至最大的斜率(相当于添加一条权值为(x+A)(y+B)的线段),单点查询该点值。


线段树的习惯不是很好……

应该树状数组也可以过……


#include <cstdio>
#include <algorithm>
#include <cstring>
#define LL long long
using namespace std;
inline int ReadInt()
{
    int flag=0;
    char ch=getchar();
    int data=0;
    while (ch<'0'||ch>'9')
    {
        if (ch=='-') flag=1;
        ch=getchar();
    }
    do
    {
        data=data*10+ch-'0';
        ch=getchar();
    }while (ch>='0'&&ch<='9');
    return data;
}
int A,B;
struct query
{
    int p,a,b,r;
}q[100005];
LL addv[2500010];
LL ans[100005];
struct node
{
    int a,b;
}sl[1000005],tmp;
int cmp2(node x,node y)
{
    return (x.b*y.a<x.a*y.b);
}
int cmp(query x,query y)
{
    return (x.p<y.p);
}
int cmp1(query x,query y)
{
    return (x.r<y.r);
}
int t[1005][1005];
int v;
void update(int o, int L, int R,int le,int ri)
{
    if (le<=L && ri>=R)
        addv[o]+=v;
    else {
        int M = (L + R)>>1;
        if (le<=M) update(o<<1,L,M,le,ri);
        if (ri>M) update(o<<1|1,M+1,R,le,ri);
    }
}

LL quer(int p,int x,int L,int R)
{
    int M = (L + R)>>1;
    LL sum=addv[x];
    if (L==R) return sum;
    if (p<=M) sum+=quer(p,x<<1,L,M);
    if (p>M) sum+=quer(p,x<<1|1,M+1,R);
    return sum;
}
int gcd(int x,int y)
{
    if (x==0) return y;
    return gcd(y%x,x);
}
int main()
{
    int T,m,ca=0,cnt=0;
    for (int i=1;i<=1000;i++)
        for (int j=1;j<=1000;j++)
            if (gcd(i,j)==1) {sl[++cnt].a=i;sl[cnt].b=j;}
    sl[++cnt].a=1;
    sl[cnt].b=1000005;
    sl[0].a=1;
    sl[0].b=0;
    sort(sl+1,sl+1+cnt,cmp2);
    for (int i=1;i<=cnt;i++)
    {
        for (int j=1;(sl[i].a*j<=1000)&&(sl[i].b*j<=1000);j++)
            t[sl[i].a*j][sl[i].b*j]=i;
    }
    scanf("%d",&T);
    while (T--)
    {
        scanf("%d%d",&A,&B);
        scanf("%d",&m);
        for (int i=1;i<=m;i++)
        {
            q[i].r=i;
            q[i].a=ReadInt();
            q[i].b=ReadInt();
            q[i].p=ReadInt();
        }
        memset(addv,0,sizeof addv);
        sort(q+1,q+m+1,cmp);
        int pt=0,r,c,le,ri,mid;
        for (int i=1;i<=m;i++)
        {
            while (q[i].p>=(pt/1000+1)&&pt<1000000) {
                pt++;
                r=(pt-1)/1000+1;
                c=(pt%1000)?(pt%1000):1000;
                v=(r+A)*(c+B);
                update(1,1,cnt,t[r][c],cnt);
            }
            tmp.a=q[i].a;
            tmp.b=q[i].b;
            le=0;
            ri=cnt;
            while (ri-le)
            {
                mid=(ri+le)>>1;
                if (cmp2(tmp,sl[mid])==0)
                    le=mid+1;
                else ri=mid;
            }
            le--;
            ans[q[i].r]=quer(le,1,1,cnt);
        }
        printf("Case #%d:\n",++ca);
        for (int i=1;i<=m;i++)
            printf("%I64d\n",ans[i]);
    }
    return 0;
}


[hdu 5032]2014北京网络赛Always Cook Mushroom 离散化+离线线段树/树状数组

标签:线段树

原文地址:http://blog.csdn.net/ahm001/article/details/39519619

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!