二维树状数组区间求和-HDU5517

(有任何问题欢迎留言或私聊 && 欢迎交流讨论哦

题意:传送门

 原题目描述在最下面。
 给出n个二元组 (a,b) ( a , b ) ,m个三元组 (c,d,e) ( c , d , e ) ,由 b=e b = e 得到一个新的三元组 (a,c,d) ( a , c , d ) ,求最大新三元组集合,满足对于三元组 (a,d,e) ( a , d , e ) 不存在三元组 (u,v,w) ( u , v , w ) 使得 ua,vd,we. u ≥ a , v ≥ d , w ≥ e .
 数据范围: n100000,m100000,a,b,e100000,c,d1000 n ≤ 100000 , m ≤ 100000 , a , b , e ≤ 100000 , c , d ≤ 1000
 参考思路:here

思路:

 本题十分类似类似 poj2352 p o j 2352 ,只不过模型由二维变成了三维。由一维树状数组优化变成了二维树状数组优化。

 显然 (a,b) ( a , b ) 对于同样的 b b 只有最大的a只有用的,所以读入时只保留最大的 a a 并记录次数。
 三元组(c,d,e)也只保留能满足 e=b e = b 的。对新的三元组 (a,c,d) ( a , c , d ) 按照 acd a , c , d 的顺序从大到小排序。 a10000,c,d1000 a ≤ 10000 , c , d ≤ 1000
 一维从大到小枚举 a a (c,d)用二维树状数组记录求和,每次先检验 (c,d)(1000,1000) ( c , d ) 到 ( 1000 , 1000 ) 矩阵内是否出现过一个三元组。若没出现就累加数量。

AC代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<assert.h>
#include<bitset>
#define lson rt<<1
#define rson rt<<1|1
#define lowbit(x) (x)&(-(x))
#define all(x) (x).begin(),(x).end()
using namespace std;
typedef long long LL;
const int INF = 0x3f3f3f3f;
const int N = (int)1e5 +107;
int n, m, a,b,c,d,e;
LL da[1010][1010];
int ba[N],cnt[N];
struct lp{
  int c,d,e;
  LL v;//记录出现次数
  lp(){}
  lp(int x,int y,int z,LL a){
    c=x;d=y;e=z;v=a;
  }
}cw[N];
bool cmp(lp &a,lp &b){
  if(a.c!=b.c) return a.c<b.c;
  if(a.d!=b.d) return a.d<b.d;
  return a.e<b.e;
}
void add(int x,int y,LL c){
  for(int i = x; i<= 1005; i += lowbit(i)){
    for(int j = y;j <= 1005; j += lowbit(j)){
      da[i][j] += c;
    }
  }
}
LL query(int x,int y){
  LL ans = 0;
  for(int i = x; i; i -= lowbit(i)){
    for(int j = y; j; j -= lowbit(j)){
      ans += da[i][j];
    }
  }
  return ans;
}
LL ask(int x1,int y1,int x2,int y2){
  return query(x2,y2)-query(x1-1,y2)-query(x2,y1-1)+query(x1-1,y1-1);
}
//控制一维单调变化,另两维二维树状数组求和优化
//类似poj2352
int main(){
#ifndef ONLINE_JUDGE
    freopen("E://ADpan//in.in", "r", stdin);
    //freopen("E://ADpan//out.out", "w", stdout);  
#endif
  int tim;
  scanf("%d", &tim);
  int tc=0;
  while(tim--){
    scanf("%d%d",&n,&m);
    memset(ba,-1,sizeof(ba));
    memset(cnt,0,sizeof(cnt));
    for(int i=0;i<n;++i){
      scanf("%d%d",&a,&b);
      if(a>ba[b]){
        ba[b]=a;
        cnt[b]=1;
      }else if(a==ba[b])cnt[b]++;
    }
    int num=0;
    for(int i=0;i<m;++i){
      scanf("%d%d%d",&c,&d,&e);
      if(ba[e]!=-1){
        cw[num++]=lp(ba[e],c,d,cnt[e]);
      }
    }
    sort(cw,cw+num,cmp);
    n=0;
    for(int i=1;i<num;++i){
      if(cw[i].e==cw[n].e&&cw[i].c==cw[n].c&&cw[i].d==cw[n].d){
        cw[n].v+=cw[i].v;
      }else cw[++n]=cw[i];
    }
    printf("Case #%d: ", ++tc);
    memset(da,0,sizeof(da));
    LL ans=0;
    for(int i=n;i>=0;--i){
      if(!ask(cw[i].d,cw[i].e,1005,1005))ans+=cw[i].v;
      add(cw[i].d,cw[i].e,1LL);
    }
    printf("%lld\n", ans);
  }
  return 0;
}


原题目描述:

这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值