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

下面是我自己的理解:

如果只有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);
}
}

  

线段树教做人系列(3) HDU 4913的更多相关文章

  1. 线段树教做人系列(2)HDU 4867 XOR

    题意:给你一个数组a,长度为.有两种操作.一种是改变数组的某个元素的值,一种是满足某种条件的数组b有多少种.条件是:b[i] <= a[i],并且b[1]^b[2]...^b[n] = k的数组 ...

  2. Codeforces 719E (线段树教做人系列) 线段树维护矩阵

    题面简洁明了,一看就懂 做了这个题之后,才知道怎么用线段树维护递推式.递推式的递推过程可以看作两个矩阵相乘,假设矩阵A是初始值矩阵,矩阵B是变换矩阵,求第n项相当于把矩阵B乘了n - 1次. 那么我们 ...

  3. 线段树教做人系列(1)HDU4967 Handling the Past

    题意:给你n组操作,分别为压栈,出栈,询问栈顶元素.每一组操作有一个时间戳,每次询问栈顶的元素的操作询问的是在他之前出现的操作,而且时间戳小于它的情况.题目中不会出现栈为空而且出栈的情况. 例如: p ...

  4. Codeforces 1136E Nastya Hasn't Written a Legend (线段树教做人系列)

    题意:有一个数组a和一个数组k,数组a一直保持一个性质:a[i + 1] >= a[i] + k[i].有两种操作:1,给某个元素加上x,但是加上之后要保持数组a的性质.比如a[i]加上x之后, ...

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

    题目链接 线段树的模板 #include<iostream> #include<cstdio> #include<cmath> #include<algori ...

  6. 线段树(区间合并)HDU - 1540

    题意:输入n,m,给定n个相互连通的村庄,有m个操作,D x,表示破坏x村庄使其与相邻的两个村庄不相通,R 表示修复上一个被破坏的村庄,与相邻的两个村庄联通.Q x表示与x相连的村庄有多少个. 思路: ...

  7. (线段树 区间查询)The Water Problem -- hdu -- 5443 (2015 ACM/ICPC Asia Regional Changchun Online)

    链接: http://acm.hdu.edu.cn/showproblem.php?pid=5443 The Water Problem Time Limit: 1500/1000 MS (Java/ ...

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

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

  9. 线段树(区间修改、区间查询) HDU 1754 I Hate It

    I Hate It Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total S ...

随机推荐

  1. 51nod 1131 数列

    http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1131 1131 覆盖数字的数量 基准时间限制:1 秒 空间限制:1310 ...

  2. L121

    今天上午签字仪式的布置与该场合的严肃性非常协调.The setting for this morning's signing ceremony matched the solemnity of the ...

  3. L118

    The company needs to focus on its biggest clients.This article discussed the events that led to her ...

  4. uva1583(暴力枚举或打表)

    紫书上的代码是打表. 我的做法是暴力枚举.注意,有多个变量时,选择枚举哪一个变量会影响到时间效率,值得考虑.由于各位数字之和最大就是五个9的和为45,所以就枚举各位数字之和比较快. #include& ...

  5. libmodbus相关资料整理

    /****************************************************************************** * libmodbus相关资料整理 * ...

  6. 系列文章--C#即时通讯开发

    对使用UDP协议和大规模即时通讯的思考   C#[Fox即时通讯核心] 开发记录之五 (客户端界面基窗体基本完成)  C#[Fox即时通讯核心] 开发记录之四(服务端多线程异步处理数据 主程序大致结构 ...

  7. 媒体查询ipad,pc端

    媒体查询 /* 判断ipad */ @media only screen and (min-device-width : 768px) and (max-device-width : 1024px){ ...

  8. grunt 压缩js css html 合并等配置与操作详解

    module.exports = function(grunt){ //1.引入 grunt.loadNpmTasks('grunt-contrib-cssmin'); grunt.loadNpmTa ...

  9. xmind的使用及入门

    初识 xmind是什么 比较 入门 下载 基本操作 主界面 美化 工具 导出 初识 xmind是什么 说白了就是传说中的思维导图,用它我们可以画出下面这些图: 额,这张图好丑. 好吧,换一张: 他就是 ...

  10. 2、配置Selenium RC

    1.相关Jar包:链接: https://pan.baidu.com/s/1YLp-_5t7heyzPg550BWTGg 密码: w7ne 2.启动Selenium的方法 (1)cmd命令进入sele ...