ZJOI2016

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ZJOI2016相关的知识,希望对你有一定的参考价值。

首先做了T2的旅行者,看到bz上面过的人数比较多。。

考试的时候完全没有想太多。一闪而过了分块思想,然后就没有然后了。。

大视野上面有题解,竟然是一个初中生写的。。?

正解其实是“分治”,每次选择中轴线,不会势能分析,感觉考场上想出来也肯定不敢打。。

#include<cstdio>
#include<algorithm>
#define inf 1000000000
#define N 100010
using namespace std;
int dis[N],ans[N],q[N],id[N],vet[N],head[N],next[N],pri[N];
int edgenum,cas,cnt,n,m;
struct node{int x1,y1,x2,y2,id;}a[N],b[N];
void add(int u,int v,int w)
{
  edgenum++;vet[edgenum]=v;next[edgenum]=head[u];
  head[u]=edgenum;pri[edgenum]=w;
  //printf("%d %d %d\n",u,v,w);
}
void push_down(int k)
{
  while(k*2<=cnt)
  {
     int k1=q[k],k2=q[k*2],k3=q[k*2+1];
     if(k*2+1<=cnt&&dis[k1]>dis[k3]&&dis[k3]<dis[k2])
     {
       id[k1]=k*2+1;id[k3]=k;swap(q[k],q[k*2+1]);
       k=k*2+1;
     }else if(dis[k1]>dis[k2])
     {
       id[k1]=k*2;id[k2]=k;swap(q[k],q[k*2]);k=k*2;
     }else break;
  }
}
void push_up(int k)
{
  while(k/2>0&&dis[q[k]]<dis[q[k/2]])
  {
    id[q[k]]=k/2;id[q[k/2]]=k;swap(q[k],q[k/2]);
    k=k/2;
  }
}
void dijk(int sta,int x1,int x2,int y1,int y2)
{
  cnt=1;q[1]=sta;id[sta]=1;dis[sta]=0;
  for(int i=x1;i<=x2;i++)
    for(int j=y1;j<=y2;j++)
     {
       int u=(i-1)*m+j;
       if(u!=sta){dis[u]=inf;q[++cnt]=u;id[u]=cnt;}
     }
  while(cnt)
  {
     int u=q[1];q[1]=q[cnt--];id[q[1]]=1;push_down(1);int e=head[u];//printf("reng=%d\n",u);
     while(e>0)
     {
       int v=vet[e],xx=(v-(v%m))/m+1,yy=v%m;if(yy==0)yy=m;if(v%m==0)xx--;
       //printf("ok=%d %d %d\n",v,xx,yy);
       if(xx>=x1&&xx<=x2&&yy>=y1&&yy<=y2)
       if(dis[v]>dis[u]+pri[e])
       {
         
         dis[v]=dis[u]+pri[e];
         //printf("ok=%d %d %d\n",u,v,dis[v]);
         push_up(id[v]);
       }
       e=next[e];  
     }  
  }     
  //printf("sta=%d\n",sta);
  for(int i=x1;i<=x2;i++)
    for(int j=y1;j<=y2;j++)
     {
       int u=(i-1)*m+j;
       //printf("dis=%d %d\n",u,dis[u]);
     }
}
void solve(int x1,int x2,int y1,int y2,int l,int r)
{
  if(l>r)return;int mid;
  if(x2-x1>y2-y1)
  {
    mid=(x1+x2)>>1;
    for(int i=y1;i<=y2;i++)
    {
      int u=(mid-1)*m+i;dijk(u,x1,x2,y1,y2);
      for(int j=l;j<=r;j++)
      {
        int u1=(a[j].x1-1)*m+a[j].y1,u2=(a[j].x2-1)*m+a[j].y2;
        int t=dis[u1]+dis[u2];
        ans[a[j].id]=min(ans[a[j].id],t);
      }
    } 
      int j=l-1,k=r+1;
      for(int i=l;i<=r;i++)if(a[i].x1<mid&&a[i].x2<mid)b[++j]=a[i];else
                           if(a[i].x1>mid&&a[i].x2>mid)b[--k]=a[i];
      for(int i=l;i<=j;i++)a[i]=b[i];solve(x1,mid-1,y1,y2,l,j);
      for(int i=k;i<=r;i++)a[i]=b[i];solve(mid+1,x2,y1,y2,k,r);  
  }else
  {
    mid=(y1+y2)>>1;
    for(int i=x1;i<=x2;i++)
    {
      int u=(i-1)*m+mid;dijk(u,x1,x2,y1,y2);
      for(int j=l;j<=r;j++)
      {
        int u1=(a[j].x1-1)*m+a[j].y1,u2=(a[j].x2-1)*m+a[j].y2;
        int t=dis[u1]+dis[u2];
        ans[a[j].id]=min(ans[a[j].id],t);
      }  
    }  
      int j=l-1,k=r+1;
      for(int i=l;i<=r;i++)if(a[i].y1<mid&&a[i].y2<mid)b[++j]=a[i];else
                           if(a[i].y1>mid&&a[i].y2>mid)b[--k]=a[i];
      for(int i=l;i<=j;i++)a[i]=b[i];solve(x1,x2,y1,mid-1,l,j);
      for(int i=k;i<=r;i++)a[i]=b[i];solve(x1,x2,mid+1,y2,k,r);
  }
}
int main()
{
freopen("4456.in","r",stdin);
freopen("4456.out","w",stdout);
  scanf("%d %d",&n,&m);
  for(int i=1;i<=n;i++)
   for(int j=1;j<m;j++)
    {
      int x,u=(i-1)*m+j,v=(i-1)*m+j+1;scanf("%d",&x);
      add(u,v,x);add(v,u,x); 
    }
       
  for(int i=1;i<n;i++)
   for(int j=1;j<=m;j++)
    {
      int x,u=(i-1)*m+j,v=i*m+j;scanf("%d",&x);
      add(u,v,x);add(v,u,x);
    }   
  scanf("%d",&cas);
  for(int i=1;i<=cas;i++)
  {
    scanf("%d%d%d%d",&a[i].x1,&a[i].y1,&a[i].x2,&a[i].y2);
    a[i].id=i;ans[i]=inf;
  } 
  solve(1,n,1,m,1,cas);
  for(int i=1;i<=cas;i++)printf("%d\n",ans[i]);
} 

 

以上是关于ZJOI2016的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ4456 [Zjoi2016]旅行者 / UOJ #184 ZJOI2016旅行者

ZJOI2016

ZJOI2016一试游记

4455[Zjoi2016]小星星 容斥+dp

[BZOJ4455][ZJOI2016]数星星(容斥DP)

bzoj4456: [Zjoi2016]旅行者