hdu5481
来源:互联网 发布:mysql my.cnf 路径 编辑:程序博客网 时间:2024/06/16 13:49
一开始尝试用线段树,结果超时。
超时的代码:
#include<stdio.h>#include<string.h>#include<iostream>#include<algorithm>using namespace std;#define N 200010#define MOD 1000000007struct 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 1000000007int 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 1000000007int 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,把所有的区间加进去后,最后求答案,是再遍历。
0 0