【TMD模拟赛】上低音号 链表

这道题一看有两个出发现点,一枚举点去找边界,想了一会就Pass了...,二是枚举相框,我们最起码枚举两个边界,然后发现平行边界更好处理,然而仍然只有30分,这个时候就来到了链表的神奇应用,我们枚举上界u,下界d在u的基础之上从下往上枚举,我们每次枚举上界的开始就把上界以下的点建成链表(它的形状大概是在从左到右的基础上对于同一列的从上倒下,就是蛇形),然后让下届去逼近并结算答案,十分巧妙。

关于链表:大概有单向链表,双向链表,以及循环链表,他们作为数据结构的应用十分狭窄,只有在特定情境下才有大用处,所以在oi层面只有双向链表有一定用处,他的删除在记录位置的前提下是O(1)的,查询O(n),插入的话主要是找到合适的位置(前驱),剩下的就是O(1)了。

#include <cstdio>
#include <cstring>
#include <algorithm>
typedef long long LL;
const int N=3065;
int pre[N],next[N],mem[N][N],last[N];
int line,column,n,k;
LL ans;
bool ex[N];
struct Point{int x,y;}p[N];
inline bool comp(Point a,Point b){return a.y<b.y||(a.y==b.y&&a.x<b.x);}
int main(){
  scanf("%d%d%d%d",&line,&column,&n,&k);
  for(int i=1;i<=n;++i)
    scanf("%d%d",&p[i].x,&p[i].y);
  std::sort(p+1,p+n+1,comp);
  for(int i=1;i<=n;++i)
    mem[p[i].x][++mem[p[i].x][0]]=i;
  for(int u=1;u<=n;++u){
    int pr=0;memset(ex,0,sizeof(ex));
    for(int i=u;i<=n;++i)
      for(int j=1;j<=mem[i][0];++j)
        ex[mem[i][j]]=true,last[mem[i][j]]=line;
    for(int i=1;i<=n;++i)
      if(ex[i])pre[i]=pr,next[pr]=i,pr=i;
    pre[n+1]=pr,next[pr]=n+1;
    for(int i=2;i<=k;++i)
      pre[n+i]=n+i-1,next[n+i-1]=n+i;
    for(int d=n;d>=u;--d){
      for(int i=1;i<=mem[d][0];++i){
        int nk=mem[d][i];
        for(int j=1;j<=k;++j)nk=next[nk];
        if(next[mem[d][i]]<=n&&p[next[mem[d][i]]].x!=d)
          ans+=(LL)(last[next[mem[d][i]]]-d+1)*
          (p[next[mem[d][i]]].y-p[pre[next[mem[d][i]]]].y)*
          (nk>n?0:column-p[nk].y+1),
          last[next[mem[d][i]]]=d-1;
        nk=pre[nk],
        ans+=(LL)(last[mem[d][i]]-d+1)*
        (p[mem[d][i]].y-p[pre[mem[d][i]]].y)*
        (nk>n?0:column-p[nk].y+1);
        for(int j=1,now=mem[d][i];j<k&&now;++j){
          now=pre[now],nk=pre[nk];
          if(now&&p[now].x!=d&&last[now]>=d)
            ans+=(LL)(last[now]-d+1)*
            (p[now].y-p[pre[now]].y)*
            (nk>n?0:column-p[nk].y+1),
            last[now]=d-1;
        }
      }
      for(int i=1;i<=mem[d][0];++i)
        next[pre[mem[d][i]]]=next[mem[d][i]],
        pre[next[mem[d][i]]]=pre[mem[d][i]];
    }
  }
  printf("%lld",ans);
}

 

posted @ 2017-10-01 20:51  TS_Hugh  阅读(246)  评论(0编辑  收藏  举报