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

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,并将询问按照极角排序,离线将询问的斜率也排序,逆时针每个点加入线段树。询问实际上就是求一个前缀和了。一边处理询问,一边处理这些点。

每次区间更新[p,1000](相当于添加一条权值为(x+A)(y+B)的线段),单点查询该点值。


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

第一版的代码输入优化4950ms险过(按照斜率离散化)

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

第二版 2859ms

#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[5005];
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 cmp1(query x,query y)
{
    return (x.b*y.a<x.a*y.b);
}
int cmp(query x,node y)
{
    return (x.b*y.a>=x.a*y.b);
}
void update(int o, int L, int R,int le,int ri,LL v)
{
    if (le<=L && ri>=R)
        addv[o]+=v;
    else {
        int M = (L + R)>>1;
        if (le<=M) update(o<<1,L,M,le,ri,v);
        if (ri>M) update(o<<1|1,M+1,R,le,ri,v);
    }
}

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 main()
{
    int T,m,ca=0,cnt=0;
    for (int i=1;i<=1000;i++)
        for (int j=1;j<=1000;j++)
        {
            sl[++cnt].a=i;
            sl[cnt].b=j;
        }
    sort(sl+1,sl+1+cnt,cmp2);
    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();
        }
        sort(q+1,q+1+m,cmp1);
        memset(addv,0,sizeof addv);
        int pt=0;
        for (int i=1;i<=m;i++)
        {
            while (pt<1000000&&cmp(q[i],sl[pt+1]))
            {
                pt++;
                update(1,1,1000,sl[pt].a,1000,(sl[pt].a+A)*(sl[pt].b+B));
            }
            ans[q[i].r]=quer(q[i].p,1,1,1000);
        }
        printf("Case #%d:\n",++ca);
        for (int i=1;i<=m;i++)
            printf("%I64d\n",ans[i]);
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值