HDU 5517 Triple ACM/ICPC 2015 Shenyang(二维树状数组)

来源:互联网 发布:js 页面加载后 合计 编辑:程序博客网 时间:2024/05/21 15:41

Triple

Time Limit: 12000/6000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 818    Accepted Submission(s): 297

Problem Description

Given the finite multi-set A of n pairs of integers, an another finite multi-set B of m triples of integers, we define the product of A and B as a multi-set

C=AB={a,c,da,bA, c,d,eB and b=e}
For each a,b,cC, its BETTER set is defined as
BETTERC(a,b,c)={u,v,wCu,v,wa,b,c, ua, vb, wc}
As a \textbf{multi-set} of triples, we define the TOP subset (as a multi-set as well) ofC, denoted by TOP(C), as
TOP(C)={a,b,cCBETTERC(a,b,c)=}
You need to compute the size of TOP(C).

Input

The input contains several test cases. The first line of the input is a single integert (1t10) which is the number of test case. Then t test cases follow.
Each test case contains three lines. The first line contains two integers n (1n105) and m (1m105) corresponding to the size of A and B respectively.
The second line contains 2×n nonnegative integers

a1,b1,a2,b2,,an,bn

which describe the multi-set A, where 1ai,bi105.
The third line contains 3×m nonnegative integers
c1,d1,e1,c2,d2,e3,,cm,dm,em

corresponding to the m triples of integers in B, where 1ci,di103 and 1ei105.

Output

For each test case, you should output the size of set TOP(C).

Sample Input

25 91 1 2 2 3 3 3 3 4 21 4 1 2 2 1 4 1 1 1 3 2 3 2 2 4 1 2 2 4 3 3 2 3 4 1 33 42 7 2 7 2 71 4 7 2 3 7 3 2 7 4 1 7

Sample Output

Case #1: 5Case #2: 12

Source

2015ACM/ICPC亚洲区沈阳站-重现赛(感谢东北大学)

Recommend

wange2014   |   We have carefully selected several similar problems for you:  6193 6192 6191 6190 6189 



        题目读清楚,脑子不混乱,思路自然就会更清晰……

        这题就是给你两个集合A和B。A中每个元素包含两个数字a和b,然后B中每个元素包含三个数字c、d和e。我们规定,如果A中的i元素的b与B中的j元素的e相同,那么把这两个元素合并成<a,c,d>加入C集合中。然后,问C集合中,有多少个元素满足C中不存在某个元素的三个数字都大于等于它且不与其相等。

        其实复述的也有点乱,好好理解一下吧……然后初始想法是,显然A中的元素,如果两个元素的b相等,而a一大一小,那么显然小的那个不会对结果产生贡献,因为对于可以与小元素配对的所以B中的元素,大元素同样也可以配对,而此时c、d相同,大元素的a更大,因此小元素没有贡献。如此,我们就可以处理出A中每一个b都只能严格对应一个数字a(可以有多个a)。然后,我们就可以合并出C集合,对于每一个B中的元素<c,d,e>我们通过刚刚那个,可以找到b对应的最大的a,就可以构成<a,c,d>,这里要注意如果有多个a,我们没必要建立多个元素,直接合并为一个并记录下个数。

        C集合出来之后,我们就来统计满足条件的元素个数。首先我们对元素按照先a后c再d的顺序排序,然后从大的开始添加。我们在合并的时候保证了a都是只有一个,但是并没有保证c,d只有一个,所以也是先把一样的合并。然后开始添加,由于从大到小添加,所以a一定是不上升的,所以如果某个元素是合法的,那么它的c和d中肯定有一个比其他所有元素大,反过来也就是不存在某个元素,使得该元素的c、d都比他小。这样相当于只有两个关联的参数,于是乎可以把c、d看作横纵坐标,每次我看坐标轴上是否有在他右上方的点,如果没有则满足条件把该点加入。即二维单点更新、区间查询,莫过于二维树状数组了。

        直到现在,才知道这道题目居然是用二维树状数组的……再次长见识了……具体见代码:

#include<bits/stdc++.h>#define LL long long#define N 100010using namespace std;struct Cset {int a,c,d;LL t;};struct Bset {int c,d,e;};struct Aset {int a,b;};Bset b[N]; Aset a[N]; Cset c[N];int n,m,h[N],tot; LL t[N];struct twoD_BIT{    int c[1010][1010];    void init() {memset(c,0,sizeof(c));}    int lowbit(int x) {return x&-x;}    LL getsum(int x,int y)    {        LL res=0;        for(int i=x;i>0;i-=lowbit(i))            for(int j=y;j>0;j-=lowbit(j))                res+=c[i][j];        return res;    }    void update(int x,int y,int val)    {        for(int i=x;i<=1000;i+=lowbit(i))            for(int j=y;j<=1000;j+=lowbit(j))                c[i][j]+=val;    }    int query(int x1,int y1,int x2,int y2)    {        return getsum(x2,y2)-getsum(x1-1,y2)-getsum(x2,y1-1)+getsum(x1-1,y1-1);    }} BIT;bool cmp(Cset a,Cset b){    return a.a==b.a? a.c==b.c?a.d<b.d:a.c<b.c : a.a<b.a;}void init(){    BIT.init(); tot=0;    memset(h,0,sizeof(h));}bool operator == (Cset a,Cset b){    return a.c==b.c&&a.a==b.a&&a.d==b.d;}int main(){    int T_T,T;    cin>>T_T;T=T_T;    while(T_T--)    {        init();        LL ans=0;        scanf("%d%d",&n,&m);        for(int i=1;i<=n;i++)        {            scanf("%d%d",&a[i].a,&a[i].b);            if (h[a[i].b]==a[i].a) t[a[i].b]++;            if (h[a[i].b]<a[i].a) h[a[i].b]=a[i].a,t[a[i].b]=1;        }        for(int i=1;i<=m;i++)        {            scanf("%d%d%d",&b[i].c,&b[i].d,&b[i].e);            if (h[b[i].e]>0) c[++tot]=Cset{h[b[i].e],b[i].c,b[i].d,t[b[i].e]};        }        n=1;        sort(c+1,c+1+tot,cmp);        for(int i=2;i<=tot;i++)            if (c[n]==c[i]) c[n].t+=c[i].t;                       else c[++n]=c[i];        for(int i=n;i>=1;i--)        {            if (!BIT.query(c[i].c,c[i].d,1000,1000)) ans+=c[i].t;            BIT.update(c[i].c,c[i].d,1);        }        printf("Case #%d: %I64d\n",T-T_T,ans);    }    return 0;}


阅读全文
0 0
原创粉丝点击