hdu5101 线段树做法

来源:互联网 发布:个人信息网络黑市 编辑:程序博客网 时间:2024/04/28 19:52

要从从n个集合里面找出两个权值之和大于k的数 问总共的方案数是多少


用线段树很傻的进行模拟 每次从里面挑选一个集合 全部删除之后 再枚举集合里面的每一个数字

然后再将这个集合插回线段树里面  nlogn的复杂度 + 很大的常数

#include<cstdio>#include<cstring>#include<string.h>#include<algorithm>using namespace std;#define LL __int64//#define LL long long#define maxn 111111#define ls (rt<<1)#define rs (rt<<1|1)#define mid ((l+r)>>1)int n,m,num[maxn],s[maxn<<2],mp[1111][111],clas[1111][111];inline void up(int rt){s[rt]=s[ls]+s[rs];}inline void build(int rt,int l,int r){    s[rt]=0;    if(l==r)return ;    build(ls,l,mid);    build(rs,mid+1,r);    up(rt);}inline void ins(int rt,int l,int r,int L,int R,int w){    if(L<=l&&r<=R){s[rt]+=w;return ;}    if(L<=mid)ins(ls,l,mid,L,R,w);    if(mid<R)ins(rs,mid+1,r,L,R,w);    up(rt);}inline int query(int rt,int l,int r,int L,int R){    if(L<=l&&r<=R)return s[rt];    int sum=0;    if(L<=mid)sum+=query(ls,l,mid,L,R);    if(mid<R)sum+=query(rs,mid+1,r,L,R);    return sum;}void solve1(){    int n,k,co,ma=0;    LL ans=(LL)0;    scanf("%d%d",&n,&k);    co=0;        for(int i=0;i<n;++i){        scanf("%d",&mp[i][0]);        for(int j=1;j<=mp[i][0];++j){            scanf("%d",&mp[i][j]);            num[co++]=mp[i][j];            clas[i][j]=mp[i][j];ma=max(ma,mp[i][j]);        }    }        sort(num,num+co);    int clc=(int)(unique(num,num+co)-num);        build(1,1,clc);        for(int i=0;i<n;++i){        for(int j=1;j<=mp[i][0];++j){            mp[i][j]=(int)(lower_bound(num,num+clc,mp[i][j])-num);            ins(1,1,clc,mp[i][j]+1,mp[i][j]+1,1);        }    }        for(int i=0;i<n;++i){        for(int j=1;j<=mp[i][0];++j){            ins(1,1,clc,mp[i][j]+1,mp[i][j]+1,-1);        }        for(int j=1;j<=mp[i][0];++j){            if(k-clas[i][j]+1>ma)continue;                        int pos=(int)(lower_bound(num,num+clc,k-clas[i][j]+1)-num);            pos+=1;                        if(pos<=clc)ans+=(LL)query(1,1,clc,pos,clc);                    }                for(int j=1;j<=mp[i][0];++j){            ins(1,1,clc,mp[i][j]+1,mp[i][j]+1,1);        }            }//    printf("%lld\n",ans/2);    printf("%I64d\n",ans/2);}int main(){    int _; scanf("%d",&_);    while(_--){        solve1();    }    return 0;}


0 0
原创粉丝点击