HDU 5517 Triple (线段树)

来源:互联网 发布:烈焰遮天 源码 双端 编辑:程序博客网 时间:2024/06/05 08:49

题意:

        有二元组(a,b),三元组(c,d,e)。当b == e时它们能构成(a,c,d)。 
        然后,当不存在(u,v,w)!=(a,b,c)且u>=a,v>=b,w>=c时,则是一个better集合里的元素。 
        问这个better集合有几个元素

思路:

        注意到数据范围
        对于 N 个二元组(a,b), M 个三元组(c,d,e)
        N,M≤1e5
        ai,bi≤1e5
        ci,di≤1e3 ei≤1e5
        假设所有bi和ei都相等
        简单的两两组合会组合出1e5*1e5种 (a,c,d)

        但考虑到条件:
        求出所有(u,v,w)!=(a,b,c)且u>=a,v>=b,w>=c
        有对于所有的 (a,b) 若存在 bi==bj 只有ai >= aj
        的点对才有可能组成新的better (a,c,d)
        即对于一类 bx 或 ex只会存在一个有效的ax
        即对于任意一个三元组(c,d,e)只会有一个ax与之组合为新的(a,c,d)
        故至多有1e5个可能的better(a,c,d)
        那么问题就变成了在1e5(a,c,d)中找better

        对于1e5个可能的better(a,c,d)
        考虑到条件:
        求出所有(u,v,w)!=(a,c,d)且u>=a,v>=c,w>=d
        我们可将其按a大在前的顺序排序
        对于之后的每个(a,c,d)都可以保证u>=a
        那么问题就变成了在1e5(c,d)中找better
        考虑到ci,di≤1e3 
        我们可以利用线段树维护对于每一种ci对应的最大值di
        做1e5次区间查询和单点更新
        对于每种(ci,di)先查询 [c,max(ci)]是否存在 dj>=di
        若存在
        则说明所有的(ci,di)(一种(ci,di)可能不止有一个)都是better
        查询后再更新ci对应的最大值di即可

代码:

#include <bits/stdc++.h>using namespace std;#define ls l,mid,rt*2#define rs mid+1,r,rt*2+1#define sf l,r,rtconst int MAXN=1e3+100;const int MAXNN=1e5+5;typedef struct Node{    int x,y,z;    bool operator < (const Node &a)const{        if(x==a.x) return y==a.y?z>a.z:y>a.y;        return x>a.x;    }}Node;int tree[4*MAXN],fast[MAXN],st,en,v,ans,fans;int t[MAXNN],cnt[MAXNN];vector <Node> a[MAXNN];map <Node,int> mp;void build(int l,int r,int rt){    tree[rt]=0;    if(l==r){fast[l]=rt;return;}    int mid=(l+r)/2;    build(ls);    build(rs);}void update(int rt){    while(rt!=0&&tree[rt]<v){        tree[rt]=v;        rt/=2;    }}void query(int l,int r,int rt){    if(st>r||en<l||tree[rt]<=ans) return ;    if(st<=l&&r<=en) ans=tree[rt];    int mid=(l+r)/2;    query(ls);    query(rs);}void ini(){    for(int i=1;i<MAXNN-1;i++)        t[i]=cnt[i]=0,a[i].clear();    mp.clear();    en=-1;    fans=0;}int main(){    int T,n,m,x,y,z;    scanf("%d",&T);    for(int Case=1;Case<=T;Case++){        ini();        scanf("%d%d",&n,&m);        for(int i=1;i<=n;i++){            scanf("%d%d",&x,&y);            if(t[y]<x) t[y]=x,cnt[y]=1;            else if(t[y]==x) cnt[y]++;        }        for(int i=1;i<=m;i++){            scanf("%d%d%d",&x,&y,&z);            if(t[z]!=0){                if(!mp[{t[z],x,y}])                    a[t[z]].push_back({t[z],x,y});                mp[{t[z],x,y}]+=cnt[z];                en=max(en,x);            }        }        build(1,en,1);        int len;        for(int i=MAXNN-1;i>0;i--){            len=a[i].size();            if(len){                sort(a[i].begin(),a[i].end());                for(int j=0;j<len;j++){                    ans=0;st=a[i][j].y;                    query(1,en,1);                    if(ans<a[i][j].z)                        fans+=mp[a[i][j]];                    v=a[i][j].z;                    update(fast[a[i][j].y]);                }            }        }        printf("Case #%d: %d\n",Case,fans);    }}


原创粉丝点击