题意及思路看这篇博客就行了,讲得很详细。

下面是我自己的理解:

如果只有2,没有3的话,做法就很简单了,只需要对数组排个序,然后从小到大枚举最大的那个数。那么它对答案的贡献为(假设这个数排序后的位置是pos)2 ^ (pos - 1) * 2 ^ a[pos]。意思是a[pos]这个数必选,其它比它小的数可选可不选,有2^(pos - 1)种情况。现在相当于变成了一个二维的问题。对于这种问题,我们常见的做法是确定一维,在从前往后扫描某一维时加上另一维对答案的贡献。对于这个题,我们可以按数组b从小到大排序,去计算a的贡献。假设现在扫描到的第pos个位置(二元组(a[i], b[i])已经按数组b排序),我们考虑来计算a[i]对答案的贡献。a对答案的贡献分为2部分,一部分是之前已经出现过的,小于等于a[i]的值,假设一共有x个,那么这部分的贡献为(2 ^ x * 2 ^ a[i]),那么大于a[i]的部分呢?其实和这个式子差不多。对于每个已经出现过,并且大于a[i]的a[j],假设已经出现过的比a[j]小的数有y个,那么贡献为2 ^ (y - 1) * 2 * a[j]。为什么是y - 1? 因为a[i]是必选的。通过观察,我们可以发现,每一个a[j]对答案的贡献,取决当前已经出现过的数中有多少个比它小的数,所以我们可以这样维护:在每次插入一个值时,先询问在这个数之前出现了多少个数(假设有x个),然后插入2 ^ x * 2 ^ a[i],询问[i,n]的区间和,就是这一阶段的答案。之后,要把[i + 1,n]中的数乘2,因为他们的前面都多了一个a[i]。

代码:

#include<bits/stdc++.h>
#define ls(x) (x << 1)
#define rs(x) ((x << 1) | 1)
#define LL long long
using namespace std;
const int maxn = 100010;
const LL mod = 1000000007;
struct node{int x, y, rank;
};
bool cmp1(node x, node y) {return x.x == y.x ? x.y < y.y : x.x < y.x;
}
bool cmp2(node x, node y) {return x.y == y.y ? x.x < y.x : x.y < y.y;
}
node a[maxn];
struct SegementTree {LL sum, cnt, lz;
};
SegementTree tr[maxn * 4];
LL qpow(LL x, LL y) {LL ans = 1;for (; y; y >>= 1) {if(y & 1) ans = (ans * x) % mod;x = (x * x) % mod;}return ans;
}
void pushup(int x) {tr[x].sum = (tr[ls(x)].sum +tr[rs(x)].sum) % mod;tr[x].cnt = (tr[ls(x)].cnt + tr[rs(x)].cnt) % mod;
}
void maintain(int x, int y) {tr[x].sum = (tr[x].sum * qpow(2, y)) % mod;tr[x].lz += y;
}
void pushdown(int x) {if(tr[x].lz) {if(tr[ls(x)].cnt) maintain(ls(x), tr[x].lz);if(tr[rs(x)].cnt) maintain(rs(x), tr[x].lz);tr[x].lz = 0;}
}
void build(int x, int l, int r) {if(l == r) {tr[x].sum = tr[x].cnt = 0;return;}int mid = (l + r) >> 1;build(ls(x), l, mid);build(rs(x), mid + 1, r);pushup(x);
}
void update_cnt(int x, int l, int r, int pos, int y, int z) {if(l == r) {tr[x].cnt = 1;tr[x].sum = (qpow(2, y) * qpow(2, z)) % mod;return;}pushdown(x);int mid = (l + r) >> 1;if(pos <= mid) update_cnt(ls(x), l, mid, pos, y, z);else update_cnt(rs(x), mid + 1, r, pos ,y, z);pushup(x);
}
void update_sum(int x, int l, int r, int ql, int qr) {if(l >= ql && r <= qr) {tr[x].lz++;tr[x].sum = (tr[x].sum * 2) % mod;return;}pushdown(x);int mid = (l + r) >> 1;if(ql <= mid) update_sum(ls(x), l, mid, ql, qr);if(qr > mid) update_sum(rs(x), mid + 1, r, ql, qr);pushup(x);
}
LL query_cnt(int x, int l, int r, int ql, int qr) {if(l >= ql && r <= qr) {return tr[x].cnt;}int mid = (l + r) >> 1;pushdown(x);LL ans = 0;if(ql <= mid) ans += query_cnt(ls(x), l, mid, ql, qr);if(qr > mid) ans += query_cnt(rs(x), mid + 1, r, ql, qr);return ans;
}
LL query_sum(int x, int l, int r, int ql, int qr) {if(l >= ql && r <= qr) {return tr[x].sum;}int mid = (l + r) >> 1;LL ans = 0;pushdown(x);if(ql <= mid) ans += query_sum(ls(x), l, mid, ql, qr);if(qr > mid) ans += query_sum(rs(x), mid + 1, r, ql, qr);return ans % mod;
}
int main() {int n;while(~scanf("%d", &n)) {for (int i = 1; i <= n; i++) {scanf("%d%d", &a[i].x, &a[i].y);}sort(a + 1, a + 1 + n, cmp1);for (int i = 1; i <= n; i++) {a[i].rank = i;}sort(a + 1, a + 1 + n, cmp2);build(1, 1, n);LL ans = 0;for (int i = 1; i <= n; i++) {LL tmp = query_cnt(1, 1, n, 1, a[i].rank);update_cnt(1, 1, n, a[i].rank, tmp, a[i].x);ans = (ans + query_sum(1, 1, n, a[i].rank, n) * qpow(3, a[i].y) % mod) % mod;if(a[i].rank != n)update_sum(1, 1, n, a[i].rank + 1, n);}printf("%lld\n", ans);}
}

  

转载于:https://www.cnblogs.com/pkgunboat/p/10550737.html

线段树教做人系列(3) HDU 4913相关推荐

  1. 线段树(单点更新,区间查询) HDU 1754 I Hate It

    题目链接 线段树的模板 1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include&l ...

  2. (线段树)Just a Hook -- hdu -- 1689

    链接: http://acm.hdu.edu.cn/showproblem.php?pid=1698 思路: 我的想法很简单,像上一题一样从后面向前面来算,前面已经覆盖的,后面自然不能再来计算了,具体 ...

  3. 线段树版子题【HDU - 1166 敌兵布阵】【HDU-1754 I Hate It】【HDU-1698 Just a Hook】【OpenJ_Bailian3439A Simple Pro】

    敌兵布阵 C国的死对头A国这段时间正在进行军事演习,所以C国间谍头子Derek和他手下Tidy又开始忙乎了.A国在海岸线沿直线布置了N个工兵营地,Derek和Tidy的任务就是要监视这些工兵营地的活动 ...

  4. 【HDU - 4509】湫湫系列故事——减肥记II(合并区间模板 or 离散化标记 or 线段树)

    题干: 虽然制定了减肥食谱,但是湫湫显然克制不住吃货的本能,根本没有按照食谱行动!  于是,结果显而易见-  但是没有什么能难倒高智商美女湫湫的,她决定另寻对策--吃没关系,咱吃进去再运动运动消耗掉不 ...

  5. HDU 4533 威威猫系列故事――晒被子(线段树区间更新+分情况推公式)

    因为马拉松初赛中吃鸡腿的题目让不少人抱憾而归,威威猫一直觉得愧对大家,这几天他悄悄搬到直角坐标系里去住了.  生活还要继续,太阳也照常升起,今天,威威猫在第一象限晒了N条矩形的被子,被子的每条边都和坐 ...

  6. 2019计蒜之道复赛-A-外教 Michale 变身大熊猫(线段树求LIS及其元素出现概率)

    时限:1000ms            空间限制:524288K 题目链接https://nanti.jisuanke.com/t/39611 外教变身萌翻小学员,VIPKID "AR 变 ...

  7. 暑期集训5:并查集 线段树 练习题G: HDU - 1754

    2018学校暑期集训第五天--并查集 线段树 练习题G  --   HDU - 1754 I Hate It 很多学校流行一种比较的习惯.老师们很喜欢询问,从某某到某某当中,分数最高的是多少.  这让 ...

  8. 暑期集训5:并查集 线段树 练习题F:  HDU - 1166 ​​​​​​​

    2018学校暑期集训第五天--并查集 线段树 练习题F  --   HDU - 1166 敌兵布阵 C国的死对头A国这段时间正在进行军事演习,所以C国间谍头子Derek和他手下Tidy又开始忙乎了.A ...

  9. 暑期集训5:并查集 线段树 练习题B: HDU - 1213 ​​​​​​​

    2018学校暑期集训第五天--并查集 线段树 练习题B  --   HDU - 1213 How Many Tables Today is Ignatius' birthday. He invites ...

最新文章

  1. 2018 ACM 国际大学生程序设计竞赛上海大都会赛重现赛 J Beautiful Numbers
  2. Resetting the root password for MySQL
  3. cocos creator 游戏源码_Cocos Creator 3D引擎源码阅读之授之以渔 源码阅读
  4. Android kotlin实现底部导航栏
  5. 魅族Flyme5.x以上系统INSTALL_FAILED_SHARED_USER_INCOMPATIBLE
  6. 我的小快排(两种分割方法)
  7. Adobe AIR移动App的互相调用实现方式
  8. Advanced clustering methods (Cure, Chameleon, Rock, Jarvis-Petrich)
  9. hdu 2642 Stars 树状数组
  10. 自己动手写操作系统(一)
  11. 面向对象程序设计第三单元总结(规格系列)
  12. 个人晋升演讲ppt_晋升面试ppt自我展示演讲稿
  13. android 手机日志查看工具,日志查看器手机版下载
  14. uniapp调用c语言方法,使用uniapp开发的app/小程序需要注意:
  15. pg_stat_database 视图 tup_returned、tup_fetched 的含义
  16. Typora Emoji图标
  17. MySQL多表联表查询
  18. JavaSE第21篇:Java之IO流下篇
  19. DaoCloud道客云原生开源项目KLTS,全称为Kubernetes Long Term Support,为Kubernetes早期版本提供长期免费的维护支持
  20. 前端学习 之 JavaScript基础

热门文章

  1. linux 卸载 flash,使用率下降到8%,Chrome 87将完全移除Flash
  2. dict是python语言的内置对象_Python内置了字典:dict的支持
  3. python函数大全和意思_python 之 内置函数大全
  4. chroot环境怎么重启linux,linux下简易chroot环境的塔建
  5. android8.1启动前台服务,Android - 保活(1)前台服务保活
  6. jQuery在同级节点中查找
  7. 【流媒体服务器的搭建】2. 源码编译安装ffmpeg
  8. 向js中添加静态方法与属性方法
  9. 评估微型计算机的主要指标,微型计算机的工作过程和主要性能指标.doc
  10. 89600 matlab,是德KEYSIGHT N9000B CXA 信号分析仪,多点触控,9 kHz 至 26.5 GHz