一开始尝试用线段树,结果超时。
超时的代码:
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
using namespace std;
#define N 200010
#define MOD 1000000007
struct node{
int l,r;
int cou;
};
int num[N];
int l[N],r[N];
int m;
struct node tree[4*N];
int alll,allr;
void lisanhua(int n){
sort(num,num+n);
m=unique(num,num+n)-num;
return;
}
void create(int root,int l,int r){
if(l+1==r){
tree[root].l=l;
tree[root].r=r;
tree[root].cou=0;
return;
}
else{
int middle=(l+r)>>1;
create(root<<1,l,middle);
create((root<<1)+1,middle,r);
tree[root].l=l;
tree[root].r=r;
tree[root].cou=0;
return;
}
}
void push_down(int root){
if(tree[root].cou){
tree[root<<1].cou+=tree[root].cou;
tree[(root<<1)+1].cou+=tree[root].cou;
tree[root].cou=0;
}
return;
}
int query(int root,int l,int r){
if(l+1==r){
return tree[root].cou;
}
else{
int middle=(r+l)>>1;
push_down(root);
if(allr<=middle){
return query(root<<1,l,middle);
}
else{
return query((root<<1)+1,middle,r);
}
}
}
void add(int root,int l,int r){
if(alll<=l&&allr>=r){//这里想错了,所以写成了 l<=alll&&r>=allr
tree[root].cou+=1;
return;
}
else{
int middle=(l+r)>>1;
if(alll<middle){
add(root<<1,l,middle);
}
if(allr>middle){
add((root<<1)+1,middle,r);
}
return;
}
}
int hush(int n){
return lower_bound(num,num+m,n)-num+1;
}
long long int km(long long int x,long long int y){
long long int ans=1;
while(y){
if(y%2){
y=y/2;
ans=ans*x%MOD;
}
y=y/2;
x=x*x%MOD;
}
return ans;
}
int main(){
int t;
int n;
int numcou;
long long int ans;
scanf("%d",&t);
while(t--){
scanf("%d",&n);
numcou=0;
for(int i=0;i<n;i++){
scanf("%d%d",&l[i],&r[i]);
num[numcou++]=l[i];
num[numcou++]=r[i];
}
lisanhua(2*n);
create(1,1,m);
ans=0;
//printf("%d\n",m);
for(int i=0;i<n;i++){
int templ=hush(l[i]);
int tempr=hush(r[i]);
for(int j=templ+1;j<=tempr;j++){
alll=j-1;
allr=j;
int tempcou=query(1,1,m);
//printf("%d %d %d %d %d\n",tempcou,num[j-1],num[j-2],j-1,j);
ans=(ans+km(2,i-tempcou)*km(2,n-i-1)%MOD*(num[j-1]-num[j-2])%MOD)%MOD;
}
alll=templ;
allr=tempr;
//printf("%d %d %d %d\n",l[i],r[i],alll,allr);
add(1,1,m);
}
printf("%lld\n",ans);
}
}
部分优化后,还是超时。
超时的代码:
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
using namespace std;
#define N 200010
#define MOD 1000000007
int cou[N*4];
int num[N];
int l[N],r[N];
int m;
int alll,allr;
long long int mi[N];
void lisanhua(int n){
sort(num,num+n);
m=unique(num,num+n)-num;
return;
}
void create(int root,int l,int r){
if(l+1==r){
cou[root]=0;
return;
}
else{
int middle=(l+r)>>1;
create(root<<1,l,middle);
create((root<<1)+1,middle,r);
cou[root]=0;
return;
}
}
void push_down(int root){
if(cou[root]){
cou[root<<1]+=cou[root];
cou[(root<<1)+1]+=cou[root];
cou[root]=0;
}
return;
}
int query(int root,int l,int r){
if(l+1==r){
return cou[root];
}
else{
int middle=(r+l)>>1;
push_down(root);
if(allr<=middle){
return query(root<<1,l,middle);
}
else{
return query((root<<1)+1,middle,r);
}
}
}
void add(int root,int l,int r){
if(alll<=l&&allr>=r){
cou[root]+=1;
return;
}
else{
int middle=(l+r)>>1;
if(alll<middle){
add(root<<1,l,middle);
}
if(allr>middle){
add((root<<1)+1,middle,r);
}
return;
}
}
int hush(int n){
return lower_bound(num,num+m,n)-num+1;
}
int main(){
int t;
int n;
int numcou;
long long int ans;
mi[0]=1;
for(int i=1;i<N;i++){
mi[i]=mi[i-1]*2%MOD;
}
scanf("%d",&t);
while(t--){
scanf("%d",&n);
numcou=0;
for(int i=0;i<n;i++){
scanf("%d%d",&l[i],&r[i]);
num[numcou++]=l[i];
num[numcou++]=r[i];
}
lisanhua(2*n);
create(1,1,m);
ans=0;
//printf("%d\n",m);
for(int i=0;i<n;i++){
int templ=hush(l[i]);
int tempr=hush(r[i]);
for(int j=templ+1;j<=tempr;j++){
alll=j-1;
allr=j;
int tempcou=query(1,1,m);
//printf("%d %d %d %d %d\n",tempcou,num[j-1],num[j-2],j-1,j);
ans=(ans+mi[i-tempcou]*mi[n-i-1]%MOD*(num[j-1]-num[j-2])%MOD)%MOD;
}
alll=templ;
allr=tempr;
//printf("%d %d %d %d\n",l[i],r[i],alll,allr);
add(1,1,m);
}
printf("%lld\n",ans);
}
}
想到可能是每一个区间都遍历一遍,会很超时,于是将计算答案留到最后,一起计算,最后整个从头到尾遍历一遍所有区间的并集就可以了。
所以整体的思路是:
每个单位段,比如说(1,2),(100,101),假设有这个单元段的区间是x个,总共是n个,那么这个单元段的贡献是 (2^x-1)*2^(n-x)。因为 l 和 r 的范围比较大,所以可以离散化后再做。
ac的代码:
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
using namespace std;
#define N 200010
#define MOD 1000000007
int cou[N*4];
int num[N];
int l[N],r[N];
int m;
int n;
int alll,allr;
long long int mi[N];
long long int ans;
void lisanhua(int n){
sort(num,num+n);
m=unique(num,num+n)-num;
return;
}
void create(int root,int l,int r){
if(l+1==r){
cou[root]=0;
return;
}
else{
int middle=(l+r)>>1;
create(root<<1,l,middle);
create((root<<1)+1,middle,r);
cou[root]=0;
return;
}
}
void push_down(int root){
if(cou[root]){
cou[root<<1]+=cou[root];
cou[(root<<1)+1]+=cou[root];
cou[root]=0;
}
return;
}
int query(int root,int l,int r){
if(l+1==r){
return cou[root];
}
else{
int middle=(r+l)>>1;
push_down(root);
if(allr<=middle){
return query(root<<1,l,middle);
}
else{
return query((root<<1)+1,middle,r);
}
}
}
void add(int root,int l,int r){
if(alll<=l&&allr>=r){
cou[root]+=1;
return;
}
else{
int middle=(l+r)>>1;
if(alll<middle){
add(root<<1,l,middle);
}
if(allr>middle){
add((root<<1)+1,middle,r);
}
return;
}
}
int hush(int n){
return lower_bound(num,num+m,n)-num+1;
}
void nodepush_down(int root,int l,int r){
if(l+1==r){
int temp=cou[root];
ans=(ans+((mi[temp]-1)%MOD+MOD)%MOD*mi[n-temp]%MOD*(num[r-1]-num[l-1])%MOD)%MOD;
return;
}
else{
int middle=(l+r)>>1;
push_down(root);
nodepush_down(root<<1,l,middle);
nodepush_down((root<<1)+1,middle,r);
return;
}
}
int main(){
int t;
int numcou;
mi[0]=1;
for(int i=1;i<N;i++){
mi[i]=mi[i-1]*2%MOD;
}
scanf("%d",&t);
while(t--){
scanf("%d",&n);
numcou=0;
for(int i=0;i<n;i++){
scanf("%d%d",&l[i],&r[i]);
num[numcou++]=l[i];
num[numcou++]=r[i];
}
lisanhua(2*n);
create(1,1,m);
//printf("%d\n",m);
for(int i=0;i<n;i++){
alll=hush(l[i]);
allr=hush(r[i]);
add(1,1,m);
}
ans=0;
nodepush_down(1,1,m);
printf("%lld\n",ans);
}
}
http://blog.csdn.net/u014679804/article/details/48770245
看别人的思路更简单,是在区间的开始+1,在区间的结束-1,把所有的区间加进去后,最后求答案,是再遍历。