首页 > 代码库 > bzoj2006 [ NOI2010 ] && bzoj3784 --点分治+线段树+堆

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 }
bzoj2006

 

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 }
bzoj3784

 

bzoj2006 [ NOI2010 ] && bzoj3784 --点分治+线段树+堆