bzoj2006 [ NOI2010 ] && bzoj3784 --点分治+线段树+堆
Posted gjghfd
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj2006 [ NOI2010 ] && bzoj3784 --点分治+线段树+堆相关的知识,希望对你有一定的参考价值。
bzoj2006:
定义一个四元组{x,l,r,w},表示左端点在x,右端点在[l,r]的超级和弦的最大美妙度在将w作为右端点时取到,w可以用前缀和+线段树/ST表求出。
对于每个i,我们将{i,i+L-1,i+R-1,w}放入一个大根堆中,每次取出美妙度最大的一个加到答案中,并将{i,l,w-1,x},{i,w+1,r,x}放入堆中。
这样就相当于将左端点在i、右端点在w的超级和弦去掉。做k次就可以了。
代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<queue> 5 #include<algorithm> 6 using namespace std; 7 inline char Nc(){ 8 static char buf[100000],*p1=buf,*p2=buf; 9 if(p1==p2){ 10 p2=(p1=buf)+fread(buf,1,100000,stdin); 11 if(p1==p2)return EOF; 12 } 13 return *p1++; 14 } 15 inline void Read(int& x){ 16 char c=Nc(),b=1; 17 for(;c<\'0\'||c>\'9\';c=Nc())if(c==\'-\')b=-1; 18 for(x=0;c>=\'0\'&&c<=\'9\';x=(x<<3)+(x<<1)+c-48,c=Nc());x*=b; 19 } 20 inline int _Max(int x,int y){return x<y?y:x;} 21 inline int _Min(int x,int y){return x<y?x:y;} 22 #define N 500010 23 #define INF 2147483647 24 int i,j,k,n,m,c[N<<2],s[N],x,L,R,t[N<<2]; 25 struct G{ 26 int x,l,r,w; 27 G(){} 28 G(int x,int l,int r,int w):x(x),l(l),r(r),w(w){} 29 bool operator<(G a)const{ 30 return s[w]-s[x-1]<s[a.w]-s[a.x-1]; 31 } 32 }tmp; 33 priority_queue<G>q; 34 long long Ans; 35 inline int Query(int Node,int l,int r,int L,int R){ 36 if(l>R||r<L)return 0; 37 if(l>=L&&r<=R)return Node; 38 int Mid=l+r>>1; 39 int Q1=Query(Node<<1,l,Mid,L,R),Q2=Query(Node<<1|1,Mid+1,r,L,R); 40 return c[Q1]>c[Q2]?Q1:Q2; 41 } 42 inline void Build(int Node,int l,int r){ 43 if(l==r){ 44 c[Node]=s[l]; 45 t[Node]=l; 46 return; 47 } 48 int Mid=l+r>>1; 49 Build(Node<<1,l,Mid); 50 Build(Node<<1|1,Mid+1,r); 51 if(c[Node<<1]>c[Node<<1|1])c[Node]=c[Node<<1],t[Node]=t[Node<<1];else 52 c[Node]=c[Node<<1|1],t[Node]=t[Node<<1|1]; 53 } 54 int main() 55 { 56 Read(n);Read(k);Read(L);Read(R); 57 for(i=1;i<=n;i++)Read(x),s[i]=s[i-1]+x; 58 Build(1,1,n);c[0]=-INF; 59 for(i=1;i+L-1<=n;i++)q.push(G(i,i+L-1,_Min(i+R-1,n),t[Query(1,1,n,i+L-1,_Min(i+R-1,n))])); 60 while(k--){ 61 tmp=q.top();q.pop(); 62 Ans+=s[tmp.w]-s[tmp.x-1]; 63 if(tmp.w>tmp.l)q.push(G(tmp.x,tmp.l,tmp.w-1,t[Query(1,1,n,tmp.l,tmp.w-1)])); 64 if(tmp.w<tmp.r)q.push(G(tmp.x,tmp.w+1,tmp.r,t[Query(1,1,n,tmp.w+1,tmp.r)])); 65 } 66 printf("%lld",Ans); 67 return 0; 68 }
bzoj3784:
这题是bzoj2006的树上版本。考虑点分治。分治到一个点时,将所有点到它的距离d求出,那么一个子树中的点的d加上另一个子树中的点的d就是一条路径。
将dfs到的点依次加入一个序列,那么序列中每个点能到的所有点就是一个区间[l,r],就可以转化为bzoj2006了。
具体看代码。
代码:
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<queue> 5 using namespace std; 6 inline char Nc(){ 7 static char buf[100000],*p1=buf,*p2=buf; 8 if(p1==p2){ 9 p2=(p1=buf)+fread(buf,1,100000,stdin); 10 if(p1==p2)return EOF; 11 } 12 return *p1++; 13 } 14 inline void Read(int& x){ 15 char c=Nc(),b=1; 16 for(;c<\'0\'||c>\'9\';c=Nc())if(c==\'-\')b=-1; 17 for(x=0;c>=\'0\'&&c<=\'9\';x=(x<<3)+(x<<1)+c-48,c=Nc());x*=b; 18 } 19 inline int _Max(int x,int y){return x>y?x:y;} 20 #define N 50010 21 #define INF 2147483647 22 struct Edge{ 23 int t,nx,w; 24 }e[N<<1]; 25 int i,j,k,n,Cnt,m,l[N<<5],r[N<<5],x,y,z,L,R,c[N<<6],Num,p[N<<6],a[N<<5],h[N],f[N],d[N],Size[N],Rt,Sum; 26 bool b[N]; 27 struct G{ 28 int l,r,w,t; 29 G(){} 30 G(int l,int r,int w,int t):l(l),r(r),w(w),t(t){} 31 bool operator<(G b)const{ 32 return a[t]+w<a[b.t]+b.w; 33 } 34 }tmp; 35 priority_queue<G>q; 36 inline void Add(int x,int y,int z){e[++Num].t=y;e[Num].w=z;e[Num].nx=h[x];h[x]=Num;} 37 inline void Get_root(int x,int F){ 38 f[x]=0;Size[x]=1; 39 for(int i=h[x];i;i=e[i].nx){ 40 int v=e[i].t; 41 if(!b[v]&&v!=F){ 42 Get_root(v,x); 43 Size[x]+=Size[v]; 44 f[x]=_Max(f[x],Size[v]); 45 } 46 } 47 f[x]=_Max(f[x],Sum-Size[x]); 48 if(f[x]<f[Rt])Rt=x; 49 } 50 inline void Dfs(int x,int F){ 51 a[++Cnt]=d[x];l[Cnt]=L;r[Cnt]=R; 52 for(int i=h[x];i;i=e[i].nx){ 53 int v=e[i].t; 54 if(!b[v]&&v!=F)d[v]=d[x]+e[i].w,Dfs(v,x); 55 } 56 } 57 inline void Solve(int x){ 58 a[++Cnt]=0;d[x]=0;L=R=Cnt;b[x]=1; 59 for(int i=h[x];i;i=e[i].nx){ 60 int v=e[i].t; 61 if(!b[v])d[v]=e[i].w,Dfs(v,x),R=Cnt; 62 } 63 for(int i=h[x];i;i=e[i].nx){ 64 int v=e[i].t; 65 if(!b[v]){ 66 f[Rt=0]=Size[v]+1;Sum=Size[v]; 67 Get_root(v,x); 68 Solve(Rt); 69 } 70 } 71 } 72 inline void Build(int Node,int l,int r){ 73 if(l==r){ 74 c[Node]=a[l]; 75 p[Node]=l; 76 return; 77 } 78 int Mid=l+r>>1; 79 Build(Node<<1,l,Mid); 80 Build(Node<<1|1,Mid+1,r); 81 if(c[Node<<1]>c[Node<<1|1])c[Node]=c[Node<<1],p[Node]=p[Node<<1];else 82 c[Node]=c[Node<<1|1],p[Node]=p[Node<<1|1]; 83 } 84 inline int Query(int Node,int l,int r,int L,int R){ 85 if(l>R||r<L)return 0; 86 if(l>=L&&r<=R)return Node; 87 int Mid=l+r>>1; 88 int Q1=Query(Node<<1,l,Mid,L,R),Q2=Query(Node<<1|1,Mid+1,r,L,R); 89 return c[Q1]>c[Q2]?Q1:Q2; 90 } 91 int main() 92 { 93 Read(n);Read(m); 94 for(i=1;i<n;i++)Read(x),Read(y),Read(z),Add(x,y,z),Add(y,x,z); 95 f[Rt=0]=n+1;Sum=n;Get_root(1,0); 96 Solve(Rt); 97 Build(1,1,Cnt);c[0]=-INF; 98 for(i=1;i<=Cnt;i++)if(l[i])q.push(G(l[i],r[i],a[i],p[Query(1,1,Cnt,l[i],r[i])])); 99 while(m--){ 100 tmp=q.top();q.pop(); 101 printf("%d\\n",tmp.w+a[tmp.t]); 102 if(tmp.t>tmp.l)q.push(G(tmp.l,tmp.t-1,tmp.w,p[Query(1,1,Cnt,tmp.l,tmp.t-1)])); 103 if(tmp.t<tmp.r)q.push(G(tmp.t+1,tmp.r,tmp.w,p[Query(1,1,Cnt,tmp.t+1,tmp.r)])); 104 } 105 return 0; 106 }
以上是关于bzoj2006 [ NOI2010 ] && bzoj3784 --点分治+线段树+堆的主要内容,如果未能解决你的问题,请参考以下文章