题目链接:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=5258

2015年ACM/ICPC沈阳赛区 I题(二维树状数组)

2015年ACM/ICPC沈阳赛区 I题(二维树状数组)

题意:给你n(n<=1e5)个正整数二元组<a,b> (1<=a,b<=1e5)

给你m(m<=1e5)个正整数三元组<c,d,e>(1<=c,d<=1e3  1<=e<=1e5)

定义新的三元组等于上述两个二元组的“积”,运算规则如下:

<a,b> * <c,d,e> =<a,c,d>  if b==e

求新的所有三元组中,有多少个三元组在凸点.(没有其它三元组比它大)

思路:本题的关键是数据范围,注意我红色标记的部分。

注意到以后,求凸点就比较容易想到二维树状数组了。但是直接暴力相乘两个二元组的话会爆炸。

注意到新的三元组的定义。也就是说二元组中b相同的,只有最大的a才会对答案有贡献。(想想是不是)

因此对于每个b,只保留最大的a。相同的累加数量。

这样和三元组做“积”之后,新的三元组的数量不会超过1e5。然后合并重复的三元组。

然后就是二维树状数组求凸点的操作了。

按a从小到大排序,相同b小的排前面,再相同c小的排前面。

然后倒着往二维树状数组里加点(b,c),如果它右上角有比他大的点,则这个新三元组对答案没贡献。

注意long long。

代码:

#include<bits/stdc++.h>
#define ll long long
#define inf 0x3f3f3f3f3f3f3f3fLL
using namespace std;
const int maxn=1010;
const int maxm=100010;
ll C[maxn][maxn];
int n,m;
int mp[maxm];
ll num[maxm];
struct node
{
    int a,b,c;
    ll sum;
    node(){}
    node(int aa,int bb,int cc,ll dd)
    {
        a=aa;b=bb;c=cc;sum=dd;
    }
    bool operator<(node aa)const
    {
        if(aa.a!=a) return a<aa.a;
        else if(aa.b!=b) return b<aa.b;
        else return c<aa.c;
    }
    node operator +(const node &aa)const
    {
        return node(a,b,c,sum+aa.sum);
    }
    bool operator ==(const node &aa)const
    {
        return (!(*this<aa||aa<*this));
    }
}st[maxm];
int lb(int x){return x&(-x);}
void add(int x,int y,ll v)
{
    for(int i=x;i<maxn;i+=lb(i))
    for(int j=y;j<maxn;j+=lb(j))
    C[i][j]+=v;
}
ll query(int x,int y)
{
    ll ans=0;
    for(int i=x;i>0;i-=lb(i))
    for(int j=y;j>0;j-=lb(j))
    {
        ans+=C[i][j];
    }
    return ans;
}
int main()
{
    int T,cas=1;
    scanf("%d",&T);
    int x,y;
    while(T--)
    {
        scanf("%d%d",&n,&m);
        memset(C,0,sizeof(C));
        memset(mp,0,sizeof(mp));
        memset(num,0,sizeof(num));
        for(int i=0;i<n;i++)
        {
            scanf("%d%d",&x,&y);
            if(mp[y]<x) {mp[y]=x;num[y]=1;}
            else if(mp[y]==x){num[y]++;}
        }
        int cnt=0;
        for(int i=0;i<m;i++)
        {
            int x,y,z;
            scanf("%d%d%d",&x,&y,&z);
            if(mp[z]) st[cnt++]=node(mp[z],x,y,num[z]);
        }
        sort(st,st+cnt);
        int tot=0;
        for(int i=1;i<cnt;i++)
        {
            if(st[tot]==st[i]) st[tot]=st[tot]+st[i];
            else st[++tot]=st[i];
        }
        ll ans=0;
        for(int i=tot;i>=0;i--)
        {
            int x=st[i].b,y=st[i].c;
            ll f=query(1000,1000)-query(x-1,1000)-query(1000,y-1)+query(x-1,y-1);
            if(!f) ans+=st[i].sum;
            add(x,y,1);
        }
        printf("Case #%d: %lld\n",cas++,ans);
    }
    return 0;
}

 

相关文章: