【题目大意】
求n个元素所有非空子集的LCM和。
【思路】
容易想到,对于一个集合LCM = 2^(max(a值)) * 3^(max(b值))。
我们将所有元素按bi排序,我们依次枚举第i个元素必须选,且不会选xj(j > i)的情况。如果第i个元素必须选,那么max(b值)就确定了。剩下的分为两部分,a值<=ai的,和a值>ai的,记前者的个数为x,后者的个数为y。如果我们不使用a值>ai的元素,那么max(a值)== ai,这样的集合种类数就是2^x,ans += 2^ai * 3^ bi * 2^x。但是如果要用a值>ai的部分呢?这个比较复杂,我们假设这样的数字一共有3个,a值的从小到大依次是aa1,aa2,aa3,这部分的和值就为:3^bi * ( a^aa1 * 2^x + a^aa2 * 2^(x+1) + a^aa3 * 2^(x+2) )。
因为新添一个xi,对于原来a值更大的那部分和,每个都会乘以2;比a值更小的,不会变换;而a值相等的,我们可以计算出增量:如果记原来a值等于ai的有z个。那么原来的值应该是(2^z - 1)*(2^x)*2^ai,现在的为(2^(z+1) - 1)*(2^x)*2^ai,增量=2^z*2^x*2^ai。
那么,我们将数字离散化,维护下个数(我用的是树状数组)和一个和值(我用的是线段树)就可以了。
//#pragma comment(linker, "/STACK:102400000,102400000")
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<cmath>
#include<cctype>
#include<string>
#include<algorithm>
#include<iostream>
#include<ctime>
#include<map>
#include<set>
using namespace std;
#define MP(x,y) make_pair((x),(y))
#define PB(x) push_back(x)
typedef __int64 LL;
//typedef unsigned __int64 ULL;
/* ****************** */
const int INF = 100011122;
const double INFF = 1e100;
const double eps = 1e-8;
const LL mod = 1000000007;
const int NN = 100010;
const int MM = 5000010;
/* ****************** */
int tf[NN];
int c[NN];
struct TR
{
int l,r;
LL sum,fg;
int mid()
{
return (l+r)>>1;
}
}tr[NN*4];
struct node
{
int ai,bi;
bool operator<(const node &tt)const
{
return bi < tt.bi;
}
}a[NN];
int lowbit(int x)
{
return x&(-x);
}
int get_sum(int x)
{
int ans = 0;
for(;x>0;x-=lowbit(x))
ans += c[x];
return ans;
}
void modify(int x,int n,int ad)
{
for(;x<=n;x+=lowbit(x))
c[x] += ad;
}
void push_up(int R)
{
tr[R].sum = tr[R<<1].sum + tr[R<<1|1].sum;
tr[R].sum %= mod;
}
void down(int R,LL cheng)
{
tr[R].fg = tr[R].fg * cheng % mod;
tr[R].sum = tr[R].sum * cheng % mod;
}
void push_down(int R)
{
if(tr[R].fg!=1)
{
down(R<<1,tr[R].fg);
down(R<<1|1,tr[R].fg);
tr[R].fg = 1;
}
}
void build(int l,int r,int R)
{
tr[R].l = l;
tr[R].r = r;
tr[R].fg = 1;
if(l==r)
{
tr[R].sum = 0;
return;
}
int mid = tr[R].mid();
build(l,mid,R<<1);
build(mid+1,r,R<<1|1);
push_up(R);
}
LL query(int l,int r,int R)
{
if(l<=tr[R].l && tr[R].r<=r)
return tr[R].sum;
push_down(R);
int mid = tr[R].mid();
LL ans = 0;
if(l <= mid)
ans += query(l,r,R<<1);
if(r >= mid+1)
ans += query(l,r,R<<1|1);
return ans%mod;
}
void update1(int l,int r,int R,LL col)
{
if(l<=tr[R].l && tr[R].r<=r)
{
down(R,col);
return;
}
push_down(R);
int mid = tr[R].mid();
if(l<=mid)
update1(l,r,R<<1,col);
if(r>=mid+1)
update1(l,r,R<<1|1,col);
push_up(R);
}
void update(int x,int R,LL col)
{
if(tr[R].l == tr[R].r)
{
tr[R].sum += col;
tr[R].sum %= mod;
return;
}
push_down(R);
int mid= tr[R].mid();
if(x<=mid)
update(x,R<<1,col);
else
update(x,R<<1|1,col);
push_up(R);
}
LL q_pow(LL x,LL n)
{
LL ans = 1, xx = x;
for(;n>0;n>>=1)
{
if(n&1)
{
ans = ans*xx%mod;
}
xx = xx*xx%mod;
}
return ans;
}
int main()
{
int i, n, tol, t;
LL ans, temp, ge, t1, t2, woca, xia;
while (scanf("%d",&n) != EOF)
{
for (i = 1; i <= n; i ++)
{
scanf("%d%d", &a[i].ai, &a[i].bi);
tf[i] = a[i].ai;
}
sort(a+1, a+1+n);
sort(tf+1, tf+1+n);
tol = unique(tf+1, tf+1+n) - tf - 1;
memset(c, 0, sizeof(c));
build(1, tol, 1);
ans = 0;
for (i = 1; i <= n; i ++)
{
t = lower_bound(tf+1, tf+1+tol, a[i].ai) - tf;
temp = q_pow(3,a[i].bi);
// <= a[i].ai 的部分
t1 = q_pow(2, a[i].ai);
ge = get_sum(t);
t1 = t1 * q_pow(2, ge);
t1 %= mod;
ans += temp*t1;
ans %= mod;
// >a[i].ai 的部分
if (t + 1 <= tol)
t2 = query(t+1, tol, 1);
else
t2 = 0;
ans += temp*t2;
ans %= mod;
//修改
if (t + 1 <= tol)
update1(t+1, tol, 1, 2);
xia = get_sum(t-1);
woca = q_pow(2,xia) * q_pow(2,a[i].ai);
woca %= mod;
woca = woca * q_pow(2,ge-xia);
woca %= mod;
update(t,1,woca);
modify(t,tol,1);
}
printf("%lld\n",ans);
}
return 0;
}