有生之年系列之几道码农题 (6/12)

VictorWonder posted @ 2015年3月24日 12:15 in 专题训练 with tags 模拟 线段树 码农题 , 2828 阅读
      Kenji's Life告诉我们,代码能力不够强是绝对不可能通关的。考虑到最近状态不对,代码能力都快变成负数了,所以决定抓紧时间,在省选前好好锻炼一下代码能力,这里推荐几道码农题供大家参考参考。

      看到这道题估计就有人要吐槽了,这种代码不超过3k的题目也能算是码农题?可持久化线段树+矩阵随便搞搞不就行了。但是,如果不准用矩阵呢?当年的我too young too naive,依靠着分类讨论大法硬生生地将这题给码了出来,然后在本地AC了——请注意,只是本地AC了而已,后来证明,手打的spj不够靠谱,程序扔到Tsinsen就出错了,一直不知道错在哪里。最近突然想到了这道题目,就扒了出来,经过一番研究后发现原来是因为输出用了%lf,改了之后又发现,被卡内存了!只好默默地将记录操作类型的op数组从int改成了char,总算是AC了。因为是很久以前的代码,代码风格有点奇怪,再加上一些改动,简直不能看,大家将就一下吧。
//分类讨论+可持久化线段树
//x1=x0*cos n-y0*sin n
//y1=x0*sin n+y0*cos n
//1-Lurk  2-Move  3-Patrol
#include <cstdio>
#include <algorithm>
#include <cmath>
#define M 100050
#define N 9000100
using namespace std;
const double pi=acos(1.0)*2;
struct node{double x,y;}a[M];
struct seg{double x,y;}lazy[N];
struct tree{int l,r;}son[N];
char op[N];
int n,m,tot,head[M],len;
char s[10];
int make(int l,int r){
  int i=++len,mid=(l+r) >> 1;
  if (l==r) {
    lazy[i].x=a[l].x;
    lazy[i].y=a[l].y;
    op[i]=1;
    return i;
  }
  son[i].l=make(l,mid);
  son[i].r=make(mid+1,r);
  return i;
}
void clean(int i,int l,int r){
  int t;
  if (!i) return;
  if (!op[i]) return;
  if (l==r) return;
  int mid=(l+r) >> 1;
  if (op[i]==1){
    t=++len;
    son[t]=son[son[i].l];
    son[i].l=t;
    t=++len;
    son[t]=son[son[i].r];
    son[i].r=t;
    lazy[son[i].l]=lazy[son[i].r]=lazy[i];
    op[son[i].l]=op[son[i].r]=op[i];
  } else if (op[i]==2){
    if (op[son[i].l]==1) {
      t=++len;
      lazy[t].x=lazy[son[i].l].x+lazy[i].x;
      lazy[t].y=lazy[son[i].l].y+lazy[i].y;
      op[t]=op[son[i].l];
      son[t]=son[son[i].l];
      son[i].l=t;
    } else if (op[son[i].l]==2){
      t=++len;
      lazy[t].x=lazy[son[i].l].x+lazy[i].x;
      lazy[t].y=lazy[son[i].l].y+lazy[i].y;
      op[t]=op[son[i].l];
      son[t]=son[son[i].l];
      son[i].l=t;
    } else if (op[son[i].l]==3) {
      clean(son[i].l,l,mid);
      t=++len;
      lazy[t]=lazy[i];
      op[t]=op[i];
      son[t]=son[son[i].l];
      son[i].l=t;
    } else if (!op[son[i].l]){
      t=++len;
      son[t]=son[son[i].l];
      son[i].l=t;
      lazy[t]=lazy[i];
      op[t]=op[i];
    }
    if (op[son[i].r]==1) {
      t=++len;
      lazy[t].x=lazy[son[i].r].x+lazy[i].x;
      lazy[t].y=lazy[son[i].r].y+lazy[i].y;
      op[t]=op[son[i].r];
      son[t]=son[son[i].r];
      son[i].r=t;
    } else if (op[son[i].r]==2){
      t=++len;
      lazy[t].x=lazy[son[i].r].x+lazy[i].x;
      lazy[t].y=lazy[son[i].r].y+lazy[i].y;
      op[t]=op[son[i].r];
      son[t]=son[son[i].r];
      son[i].r=t;
    } else if (op[son[i].r]==3) {
      clean(son[i].r,mid+1,r);
      t=++len;
      lazy[t]=lazy[i];
      op[t]=op[i];
      son[t]=son[son[i].r];
      son[i].r=t;
    } else if (!op[son[i].r]){
      t=++len;
      son[t]=son[son[i].r];
      son[i].r=t;
      lazy[t]=lazy[i];
      op[t]=op[i];
    }
  } else if (op[i]==3){
    if (op[son[i].l]==3) {
      t=++len;
      op[t]=3;
      lazy[t].x=lazy[son[i].l].x+lazy[i].x;
      son[t]=son[son[i].l];
      son[i].l=t;
    } else if (op[son[i].l]==2) {
      clean(son[i].l,l,mid);
      t=++len;
      lazy[t]=lazy[i];
      op[t]=op[i];
      son[t]=son[son[i].l];
      son[i].l=t;
    } else if (op[son[i].l]==1) {
      t=++len;
      lazy[t].x=lazy[son[i].l].x*cos(lazy[i].x)-lazy[son[i].l].y*sin(lazy[i].x);
      lazy[t].y=lazy[son[i].l].x*sin(lazy[i].x)+lazy[son[i].l].y*cos(lazy[i].x);
      op[t]=1;
      son[t]=son[son[i].l];
      son[i].l=t;
    } else if (!op[son[i].l]){
      t=++len;
      son[t]=son[son[i].l];
      son[i].l=t;
      lazy[t]=lazy[i];
      op[t]=op[i];
    }
    if (op[son[i].r]==3) {
      t=++len;
      op[t]=3;
      lazy[t].x=lazy[son[i].r].x+lazy[i].x;
      son[t]=son[son[i].r];
      son[i].r=t;
    } else if (op[son[i].r]==2) {
      clean(son[i].r,mid+1,r);
      t=++len;
      lazy[t]=lazy[i];
      op[t]=op[i];
      son[t]=son[son[i].r];
      son[i].r=t;
    } else if (op[son[i].r]==1) {
      t=++len;
      lazy[t].x=lazy[son[i].r].x*cos(lazy[i].x)-lazy[son[i].r].y*sin(lazy[i].x);
      lazy[t].y=lazy[son[i].r].x*sin(lazy[i].x)+lazy[son[i].r].y*cos(lazy[i].x);
      op[t]=1;
      son[t]=son[son[i].r];
      son[i].r=t;
    } else if (!op[son[i].r]){
      t=++len;
      son[t]=son[son[i].r];
      son[i].r=t;
      lazy[t]=lazy[i];
      op[t]=op[i];
    }
  } op[i]=0;
}
int change_lurk(int i,int l,int r,int x,int y){
  int t=++len;
  if (x<=l&&y>=r){
    op[t]=1;
    lazy[t].x=lazy[t].y=0.0;
    son[t]=son[i];
    return t;
  }
  clean(i,l,r);
  son[t]=son[i];
  int mid=(l+r)>>1;
  if (x<=mid) son[t].l=change_lurk(son[i].l,l,mid,x,y);
  if (y>mid) son[t].r=change_lurk(son[i].r,mid+1,r,x,y);
  return t;
}
int change_move(int i,int l,int r,int x,int y,double x1,double y1){
  int t=++len;
  if (x<=l&&y>=r){
    if (op[i]==1) {
      op[t]=1;
      lazy[t].x=lazy[i].x+x1;
      lazy[t].y=lazy[i].y+y1;
      son[t]=son[i];
      return t;
    } else if (op[i]==2){
      op[t]=2;
      lazy[t].x=lazy[i].x+x1;
      lazy[t].y=lazy[i].y+y1;
      son[t]=son[i];
      return t;
    } else if (op[i]==3){
      clean(i,l,r);
      op[t]=2;
      lazy[t].x=x1;
      lazy[t].y=y1;
      son[t]=son[i];
      return t;
    } else if (!op[i]){
      op[t]=2;
      lazy[t].x=x1;
      lazy[t].y=y1;
      son[t]=son[i];
      return t;
    }
  }
  clean(i,l,r);
  son[t]=son[i];
  int mid=(l+r)>>1;
  if (x<=mid) son[t].l=change_move(son[i].l,l,mid,x,y,x1,y1);
  if (y>mid) son[t].r=change_move(son[i].r,mid+1,r,x,y,x1,y1);
  return t;
}
int change_patrol(int i,int l,int r,int x,int y,double sita){
  int t=++len;
  if (x<=l&&y>=r){
    if (op[i]==1){
      op[t]=1;
      lazy[t].x=lazy[i].x*cos(sita)-lazy[i].y*sin(sita);
      lazy[t].y=lazy[i].x*sin(sita)+lazy[i].y*cos(sita);
      son[t]=son[i];
      return t;
    } else if (op[i]==2){
      clean(i,l,r);
      op[t]=3;
      lazy[t].x=sita;
      son[t]=son[i];
      return t;
    } else if (op[i]==3){
      op[t]=3;
      lazy[t].x=lazy[i].x+sita;
      son[t]=son[i];
      return t;
    } else if (!op[i]){
      op[t]=3;
      lazy[t].x=sita;
      son[t]=son[i];
      return t;
    }
  }
  clean(i,l,r);
  son[t]=son[i];
  int mid=(l+r)>>1;
  if (x<=mid) son[t].l=change_patrol(son[i].l,l,mid,x,y,sita);
  if (y>mid) son[t].r=change_patrol(son[i].r,mid+1,r,x,y,sita);
  return t;
}
int updata(int i,int l,int r,int x){
  clean(i,l,r);
  if (l==r) return i;
  int mid=(l+r)>>1;
  return x<=mid?updata(son[i].l,l,mid,x):updata(son[i].r,mid+1,r,x);
}
int main(){
  int i,l,r,k;double x,y;
  for (scanf("%d",&n),i=1;i<=n;i++) scanf("%lf%lf",&a[i].x,&a[i].y);
  scanf("%d",&m);
  head[0]=make(1,n);
  while (m--){
    scanf("%s",&s);
    if (s[0]=='A'){
      scanf("%d",&k);
      i=updata(head[tot],1,n,k);
      printf("%.10f %.10f\n",lazy[i].x,lazy[i].y);
    } else if (s[0]=='C') {
      scanf("%d",&k);
      tot-=k;
    } else if (s[0]=='R') {
      scanf("%d",&k);
      tot+=k;
    } else if (s[0]=='L') {
      scanf("%d%d",&l,&r);
      head[++tot]=change_lurk(head[tot-1],1,n,l,r);
    } else if (s[0]=='M') {
      scanf("%d%d%lf%lf",&l,&r,&x,&y);
      head[++tot]=change_move(head[tot-1],1,n,l,r,x,y);
    } else if (s[0]=='P') {
      scanf("%d%d%lf",&l,&r,&x);
      head[++tot]=change_patrol(head[tot-1],1,n,l,r,x);
    }
  }
  return 0;
}
 
      首先申明一句,我发这篇文章绝对不是在黑卓亮,前两题都是他出的这只是一个小小的巧合,不要在意这些细节。这道题是ZJOI 2014 day1 T1,考场上我打了个暴力拿了20分,结果出来后Claris就告诉我这道题要用线段树(怎么又是线段树)。虽然很早就知道标算怎么写了,结果一直没有这个胆量,直到昨天,花了三个多小时,硬着头皮终于码出来了,多亏了手头的数据,否则应该是怎么都不能AC的了。(这再次说明这次省选我就要滚粗了)
//线段树+拓扑
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int N=100010;
const int M=7501000;
const int infi=1000000;
struct node{int x,y;}p[N<<1];
struct seg{int l,r,c,max,min; bool f;}t[M];
char s[10];
int n,m,q,tot=1,len;
int head[N],root[N];
inline void read(int &a) {
    char ch; while (!((ch=getchar())>='0'&&ch<='9'));
    a=ch-'0'; while ((ch=getchar())>='0'&&ch<='9') (a*=10)+=ch-'0';
}
//初始化
inline void add(int &i,int l,int r,int x,int y) {
    if (!i) i=++len;
    t[i].f=1;
    if (l==r) {
        t[i].c=y;
        t[i].min=l;
        t[i].max=l;
        return;
    } int mid=(l+r)>>1;
    if (x<=mid) add(t[i].l,l,mid,x,y);
    else add(t[i].r,mid+1,r,x,y);
    t[i].min=min(t[t[i].l].min,t[t[i].r].min);
    t[i].max=max(t[t[i].l].max,t[t[i].r].max);
}
inline void init() {
    t[0].min=infi;
    for (int i=2;i<=tot;i++) {
        add(head[p[i].x],1,m,p[i].y,i>>1);
        add(root[p[i].y],1,n,p[i].x,i>>1);
    }
}
//模拟
int c[2];
inline int getid1(int i,int l,int r,int x,int y,int k) {
    if (l==r) {
        c[k]=t[i].c;
        return l;
    } int mid=(l+r)>>1;
    if (y>mid&&t[t[i].r].min<=y) return getid1(t[i].r,mid+1,r,x,y,k);
    if (x<=mid&&t[t[i].l].max>=x) return getid1(t[i].l,l,mid,x,y,k);
    c[k]=0; return 0;
}
inline int getid2(int i,int l,int r,int x,int y,int k) {
    if (l==r) {
        c[k]=t[i].c;
        return l;
    } int mid=(l+r)>>1;
    if (x<=mid&&t[t[i].l].max>=x) return getid2(t[i].l,l,mid,x,y,k);
    if (y>mid&&t[t[i].r].min<=y) return getid2(t[i].r,mid+1,r,x,y,k);
    c[k]=0; return 0;
}
inline void change(int i,int l,int r,int x) {
    if (l==r) {
        t[i].min=infi;
        t[i].max=0;
        t[i].c=0;
        return;
    } int mid=(l+r)>>1;
    if (x<=mid) change(t[i].l,l,mid,x);
    else change(t[i].r,mid+1,r,x);
    t[i].min=min(t[t[i].l].min,t[t[i].r].min);
    t[i].max=max(t[t[i].l].max,t[t[i].r].max);
}
inline void simulate() {
    int i,q,x,y,x1,y1,x2,y2,ans=0;
    for (read(q),i=1;i<=q;i++) {
        read(x); read(y);
        scanf("%s",&s);
        switch(s[0]) {
            case 'U' : y1=y; x1=getid1(root[y],1,n,1,x,0); break;
            case 'D' : y1=y; x1=getid2(root[y],1,n,x,n,0); break;
            case 'L' : x1=x; y1=getid1(head[x],1,m,1,y,0); break;
            case 'R' : x1=x; y1=getid2(head[x],1,m,y,m,0); break;
        } if ((x1==x&&y1==y)||!c[0]) continue;
        scanf("%s",&s);
        switch(s[0]) {
            case 'U' : y2=y; x2=getid1(root[y],1,n,1,x,1); break;
            case 'D' : y2=y; x2=getid2(root[y],1,n,x,n,1); break;
            case 'L' : x2=x; y2=getid1(head[x],1,m,1,y,1); break;
            case 'R' : x2=x; y2=getid2(head[x],1,m,y,m,1); break;
        } if ((x2==x&&y2==y)||!c[1]) continue;
        if (c[0]!=c[1]) continue;
        else ans++;
        change(head[x1],1,m,y1);
        change(head[x2],1,m,y2);
        change(root[y1],1,n,x1);
        change(root[y2],1,n,x2);
    } printf("%d ",ans);
}
//拓扑
int Q[N],L,R,op[N],type[N],cnt;
bool in[N];
inline void del(int i,int l,int r,int x) {
    if (l==r) {
        t[i].f=0;
        t[i].c=0;
        t[i].min=infi;
        t[i].max=0;
        return;
    } int mid=(l+r)>>1;
    if (x<=mid) del(t[i].l,l,mid,x);
    else del(t[i].r,mid+1,r,x);
    t[i].f=t[t[i].l].f|t[t[i].r].f;
    t[i].min=min(t[t[i].l].min,t[t[i].r].min);
    t[i].max=max(t[t[i].l].max,t[t[i].r].max);
}
inline bool ask(int i,int l,int r,int x,int y) {
    if (x>y) return 1;
    if (!i) return 0;
    if (!t[i].f) return 0;
    if (x<=l&&y>=r) return t[i].f;
    int mid=(l+r)>>1; bool ok=0;
    if (x<=mid) ok|=ask(t[i].l,l,mid,x,y);
    if (y>mid) ok|=ask(t[i].r,mid+1,r,x,y);
    return ok;
}
inline bool check(int i) {
    int x=i<<1,y=i<<1|1;
    int x1=min(p[x].x,p[y].x);
    int x2=max(p[x].x,p[y].x);
    int y1=min(p[x].y,p[y].y);
    int y2=max(p[x].y,p[y].y);
    if (y1==y2) {
        if (!ask(root[y1],1,n,x1+1,x2-1)) {
            in[Q[++R]=i]=1; type[R]=1;
            return true;
        } else return false;
    } else if (x1==x2) {
        if (!ask(head[x1],1,m,y1+1,y2-1)) {
            in[Q[++R]=i]=1; type[R]=2;
            return true;
        } else return false;
    } else {
        if ((p[x].x==x1&&p[x].y==y1)||(p[y].x==x1&&p[y].y==y1)) {
            if (!ask(head[x1],1,m,y1+1,y2)&&!ask(root[y2],1,n,x1,x2-1)) {
                in[Q[++R]=i]=1; type[R]=3;
                return true;
            }
            if (!ask(head[x2],1,m,y1,y2-1)&&!ask(root[y1],1,n,x1+1,x2)) {
                in[Q[++R]=i]=1; type[R]=4;
                return true;
            }
        } else {
            if (!ask(head[x1],1,m,y1,y2-1)&&!ask(root[y1],1,n,x1,x2-1)) {
                in[Q[++R]=i]=1; type[R]=5;
                return true;
            }
            if (!ask(head[x2],1,m,y1+1,y2)&&!ask(root[y2],1,n,x1+1,x2)) {
                in[Q[++R]=i]=1; type[R]=6;
                return true;
            }
        }
    } return false;
}
inline void modify(int x,int y) {
    int x1,y1;
    getid1(root[y],1,n,1,x-1,0);
    if (!in[c[0]]) check(c[0]);
    getid2(root[y],1,n,x+1,n,0);
    if (!in[c[0]]) check(c[0]);
    getid1(head[x],1,m,1,y-1,0);
    if (!in[c[0]]) check(c[0]);
    getid2(head[x],1,m,y+1,m,0);
    if (!in[c[0]]) check(c[0]);
}
inline void topology() {
    int i,x,y,x1,x2,y1,y2; init(); in[0]=1;
    for (int i=1;i<=q;i++) check(i);
    for (L=1;L<=R;L++,cnt++) {
        x=Q[L]<<1; y=Q[L]<<1|1;
        del(head[p[x].x],1,m,p[x].y);
        del(root[p[x].y],1,n,p[x].x);
        del(head[p[y].x],1,m,p[y].y);
        del(root[p[y].y],1,n,p[y].x);
        modify(p[x].x,p[x].y);
        modify(p[y].x,p[y].y);
    }
    printf("%d\n",cnt);
    for (i=1;i<=cnt;i++) {
        x=Q[i]<<1; y=Q[i]<<1|1;
        x1=min(p[x].x,p[y].x);
        x2=max(p[x].x,p[y].x);
        y1=min(p[x].y,p[y].y);
        y2=max(p[x].y,p[y].y);
        if (type[i]==1) printf("%d %d U D\n",x1+1,y1);
        else if (type[i]==2) printf("%d %d L R",x1,y1+1);
        else if (type[i]==3) printf("%d %d L D\n",x1,y2);
        else if (type[i]==4) printf("%d %d R U\n",x2,y1);
        else if (type[i]==5) printf("%d %d R D\n",x1,y1);
        else if (type[i]==6) printf("%d %d L U\n",x2,y2);
    }
}
int main() {
    read(n); read(m); read(q);
    for (int i=1;i<=q;i++) {
        tot++; read(p[tot].x); read(p[tot].y);
        tot++; read(p[tot].x); read(p[tot].y);
    } init(); simulate(); topology();
    return 0;
}
 
      因为很重要,所以要说两遍:我发这篇文章绝对不是在黑卓亮。不管你信不信,反正我是信了。这道题目有一共三个大的坑点:1、读入很坑,Pascal选手有EOLN很方便,C++选手就比较苦逼了(虽然听说也有EOLN类似的东西,但我不会用TAT),只能用gets()读入再根据空格分离。2、构建那个模型很麻烦,我的构建方法是先确定一个顶点,再从这个顶点补完正方体的三条棱,最后,根据其中两条棱确定一个平面,然后再将剩下的一层一层补完,只能说是各种蛋疼。3、搜索常数大点就会超时,我原先的做法是,搜索到n+1步的时候就进行print()操作,统计一下和,本地开O2最慢的点要跑3.5s,BZOJ上是10s卡过去的,后来听从了Claris的建议,变成了边搜索边求和,结果本地瞬间跑到了0.5s。所以说,搜索的姿势很重要。最后,给出20.8k的标程,大家感受感受。
//搜索
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int N=75;
const int M=345000;
struct node{int x,y,z;}p[M],h[10];
char S[110];
int n,m,ind,g[N][N][N],f[N][N][N];
int b[M],c[N],tot,v[M][N];
bool vis[M];
// g[i][j][k]表示第i层第j行第k个
void read(int &a) { a=0; while (S[ind]!=' ') a=(a*10)+S[ind]-'0',ind++;}
bool check(int x,int y) {
    for (int i=1;i<=v[x][0];i++) if (v[x][i]==y) return true;
    return false;
}
void work1() {
    int i,j,x;
    for (i=1;i<=n;i++) if (v[i][0]==3) {
        g[1][1][1]=i;
        vis[i]=true;
        break;
    }
    for (i=1;i<m;i++) {
        x=g[1][1][i];
        for (j=1;j<=v[x][0];j++) {
            if (vis[v[x][j]]) continue;
            if (v[v[x][j]][0]==4||v[v[x][j]][0]==3) {
                vis[v[x][j]]=true;
                g[1][1][i+1]=v[x][j];
                break;
            }
        }
    }
    for (i=1;i<m;i++) {
        x=g[1][i][1];
        for (j=1;j<=v[x][0];j++) {
            if (vis[v[x][j]]) continue;
            if (v[v[x][j]][0]==4||v[v[x][j]][0]==3) {
                vis[v[x][j]]=true;
                g[1][i+1][1]=v[x][j];
                break;
            }
        }
    }
    for (i=1;i<m;i++) {
        x=g[i][1][1];
        for (j=1;j<=v[x][0];j++) {
            if (vis[v[x][j]]) continue;
            if (v[v[x][j]][0]==4||v[v[x][j]][0]==3) {
                vis[v[x][j]]=true;
                g[i+1][1][1]=v[x][j];
                break;
            }
        }
    }
}
void work2(int t) {
    int i,j,k,x,y;
    for (i=2;i<=m;i++) for (j=2;j<=m;j++) {
        x=g[t][i-1][j];
        y=g[t][i][j-1];
        for (k=1;k<=v[x][0];k++) {
            if (vis[v[x][k]]) continue;
            if (check(y,v[x][k])) {
                vis[v[x][k]]=true;
                g[t][i][j]=v[x][k];
            }
        }
    }
}
void work3(int k) {
    int i,j,x,y,z,w;
    for (i=2;i<=m;i++) {
        x=g[k][1][i-1];
        y=g[k-1][1][i];
        for (j=1;j<=v[x][0];j++) {
            if (vis[v[x][j]]) continue;
            if (check(y,v[x][j])) {
                vis[v[x][j]]=true;
                g[k][1][i]=v[x][j];
                break;
            }
        }
    }
    for (i=2;i<=m;i++) {
        x=g[k][i-1][1];
        y=g[k-1][i][1];
        for (j=1;j<=v[x][0];j++) {
            if (vis[v[x][j]]) continue;
            if (check(y,v[x][j])) {
                vis[v[x][j]]=true;
                g[k][i][1]=v[x][j];
                break;
            }
        }
    }
}
void work4() {
    int i,j,k,t,x,y,z,w;
    for (i=2;i<=m;i++) {
        work3(i);
        work2(i);
    }
}
void work5() {
    int i,j,k;
    for (i=1;i<=m;i++) for (j=1;j<=m;j++) for (k=1;k<=m;k++) {
        p[g[i][j][k]].x=i;
        p[g[i][j][k]].y=j;
        p[g[i][j][k]].z=k;
        g[i][j][k]=b[g[i][j][k]];
    } for (i=1;i<=tot;i++) h[i]=p[c[i]];
}
//搜索
int t[N][N][N],tmp;
int MAX,MIN=1000000000;
void search(int step) {
    if (step==tot+1) {
        if (tmp>MAX) MAX=tmp;
        if (tmp<MIN) MIN=tmp;
        return;
    }
    int i,x=h[step].x,y=h[step].y,z=h[step].z;
    for (i=1;i<x;i++) {
        if (!t[i][y][z]) tmp+=g[i][y][z];
        t[i][y][z]++;
    } search(step+1);
    for (i=1;i<x;i++) {
        t[i][y][z]--;
        if (!t[i][y][z]) tmp-=g[i][y][z];
    }
    for (i=x+1;i<=m;i++) {
        if (!t[i][y][z]) tmp+=g[i][y][z];
        t[i][y][z]++;
    } search(step+1);
    for (i=x+1;i<=m;i++) {
        t[i][y][z]--;
        if (!t[i][y][z]) tmp-=g[i][y][z];
    }
    for (i=1;i<y;i++) {
        if (!t[x][i][z]) tmp+=g[x][i][z];
        t[x][i][z]++;
    } search(step+1);
    for (i=1;i<y;i++) {
        t[x][i][z]--;
        if (!t[x][i][z]) tmp-=g[x][i][z];
    }
    for (i=y+1;i<=m;i++) {
        if (!t[x][i][z]) tmp+=g[x][i][z];
        t[x][i][z]++;
    } search(step+1);
    for (i=y+1;i<=m;i++) {
        t[x][i][z]--;
        if (!t[x][i][z]) tmp-=g[x][i][z];
    }
    for (i=1;i<z;i++) {
        if (!t[x][y][i]) tmp+=g[x][y][i];
        t[x][y][i]++;
    } search(step+1);
    for (i=1;i<z;i++) {
        t[x][y][i]--;
        if (!t[x][y][i]) tmp-=g[x][y][i];
    }
    for (i=z+1;i<=m;i++) {
        if (!t[x][y][i]) tmp+=g[x][y][i];
        t[x][y][i]++;
    } search(step+1);
    for (i=z+1;i<=m;i++) {
        t[x][y][i]--;
        if (!t[x][y][i]) tmp-=g[x][y][i];
    }
}
int main() {
    int i,j,x,k,len;
    //读入数据
    scanf("%d\n",&m); n=m*m*m;
    for (i=1;i<=n;i++) {
        ind=0; gets(S);
        len=strlen(S);
        S[len]=' ';
        S[len+1]='#';
        read(b[i]); ind++;
        if (!b[i]) c[++tot]=i;
        for (;S[ind]!='#';ind++) read(v[i][++v[i][0]]);
    } work1(); work2(1);
    work4(); work5();
    search(1); printf("%d %d\n",MIN,MAX);
    return 0;
}
/*
 * 2014-04-09  Token  <token@token-HP-ENVY-14-SPECTRE-Notebook-PC>

 * 
 */
#include <cstdio>
#include <cstring>
#include <cctype>
#include <cmath>
#include <ctime>
#include <cstdlib>
#include <cstdarg>
#include <iostream>
#include <fstream>
#include <iomanip>
#include <sstream>
#include <exception>
#include <stdexcept>
#include <memory>
#include <locale>
#include <bitset>
#include <deque>
#include <list>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <vector>
#include <algorithm>
#include <iterator>
#include <functional>
#include <string>
#include <complex>
#include <valarray>
#include <climits>

using namespace std;

template <class T> inline T checkmin(T &a, T b) {
	return (a < b) ? a : a = b;
}

template <class T> inline T checkmax(T &a, T b) {
	return (a > b) ? a : a = b;
}

namespace Poor {
	const int MaxiN = 12;
	const int MaxiA = 82;
	const int MaxiV = MaxiA * MaxiA * MaxiA;
	
	int A, N, NXYGroup;
	int Ans1, Ans2;
	bool Known[MaxiV];
	int Deg[MaxiV], Value[MaxiV], X[MaxiV], Y[MaxiV], Z[MaxiV];
	int Beauty[MaxiA][MaxiA][MaxiA], XSum[MaxiA][MaxiA][MaxiA], YSum[MaxiA][MaxiA][MaxiA], ZSum[MaxiA][MaxiA][MaxiA];
	int LightID[MaxiN];
	int XSorted[MaxiN][MaxiN], YSorted[MaxiN][MaxiN], ZSorted[MaxiN][MaxiN];
	int XYGroup[MaxiN];
	bool Set[MaxiA][MaxiA][MaxiA];
	int Queue[MaxiV];
	
	struct TEdge {
		int t;
		TEdge *n;
		TEdge(int _t, TEdge *_n): t(_t), n(_n) {}
	};
	
	TEdge *Adj[MaxiV];

	inline int get_line(FILE *fp, int x[]) {
		int p;
		int num = 0, plc = 0;
		p = fgetc(fp);
		while (p != '\n' && p != EOF)
		{
			if (p == ' ') {
				x[plc] = num;
				++ plc;
				num = 0;
			}
			else
				num = num * 10 + p - '0';
			p = fgetc(fp);
		}
		x[plc] = num;
		++ plc;
		return plc;
	}
	
	void Import(FILE *fi) {
		int arr[10];
		get_line(fi, arr);
		A = arr[0];
		for (int i = 1; i <= A * A * A; ++ i) {
			Deg[i] = get_line(fi, arr) - 1;
			Value[i] = arr[0];
			Adj[i] = NULL;
			for (int j = 1; j <= Deg[i]; ++ j)
				Adj[i] = new TEdge(arr[j], Adj[i]);
		}
	}
	
	void Export(FILE *fo) {
		fprintf(fo, "%d %d\n", Ans1, Ans2);
	}
	
	inline bool OnlyOne(int i) {
		return (X[i] != 0) + (Y[i] != 0) + (Z[i] != 0) == 1;
	}
	
	inline void GoDirect(int i, int j) {
		X[i] = X[j] + (X[j] != 0);
		Y[i] = Y[j] + (Y[j] != 0);
		Z[i] = Z[j] + (Z[j] != 0);
	}
	
	inline void Rec(int i) {
		Set[X[i]][Y[i]][Z[i]] = true;
	}
	
	inline bool CanKnow(int i) {
		int bx = 15, by = 15, bz = 15;
		int arr1[4], arr2[4], arr3[4];
		int n1 = 0, n2 = 0, n3 = 0;
		for (TEdge *e = Adj[i]; e; e = e->n)
			if (Known[e->t])
			{
				int t = (X[e->t] & 3);
				if ((bx >> t) & 1) {
					bx ^= (1 << t);
					arr1[n1 ++] = X[e->t];
				}
				t = (Y[e->t] & 3);
				if ((by >> t) & 1) {
					by ^= (1 << t);
					arr2[n2 ++] = Y[e->t];
				}
				t = (Z[e->t] & 3);
				if ((bz >> t) & 1) {
					bz ^= (1 << t);
					arr3[n3 ++] = Z[e->t];
				}
			}
		int Cnt = 0;
		for (int *ita = arr1; ita != arr1 + n1; ++ ita)
			for (int *itb = arr2; itb != arr2 + n2; ++ itb)
				for (int *itc = arr3; itc != arr3 + n3; ++ itc)
					if (!Set[*ita][*itb][*itc])
						++ Cnt;
		return (Cnt == 1);
	}
	
	inline void Know(int i)
	{
		int bx = 15, by = 15, bz = 15;
		int arr1[4], arr2[4], arr3[4];
		int n1 = 0, n2 = 0, n3 = 0;
		for (TEdge *e = Adj[i]; e; e = e->n)
			if (Known[e->t])
			{
				int t = (X[e->t] & 3);
				if ((bx >> t) & 1) {
					bx ^= (1 << t);
					arr1[n1 ++] = X[e->t];
				}
				t = (Y[e->t] & 3);
				if ((by >> t) & 1) {
					by ^= (1 << t);
					arr2[n2 ++] = Y[e->t];
				}
				t = (Z[e->t] & 3);
				if ((bz >> t) & 1) {
					bz ^= (1 << t);
					arr3[n3 ++] = Z[e->t];
				}
			}
		for (int *ita = arr1; ita != arr1 + n1; ++ ita)
			for (int *itb = arr2; itb != arr2 + n2; ++ itb)
				for (int *itc = arr3; itc != arr3 + n3; ++ itc)
					if (!Set[*ita][*itb][*itc])
					{
						X[i] = *ita;
						Y[i] = *itb;
						Z[i] = *itc;
						return;
					}
	}
	
	void Do()
	{
		memset(Set, 0, sizeof(Set));
		int Origin = 1;
		for (int i = 1; i <= A * A * A; ++ i)
			if (Deg[i] == 3)
				Origin = i;
		X[Origin] = Y[Origin] = Z[Origin] = 0;
		Known[Origin] = 1;
		Rec(Origin);
		int Head = 0, Tail = 0;
		int tmp = 0;
		for (TEdge *e = Adj[Origin]; e; e = e->n)
		{
			++ tmp;
			X[e->t] = Y[e->t] = Z[e->t] = 0;
			if (tmp == 1)
				X[e->t] = 1;
			if (tmp == 2)
				Y[e->t] = 1;
			if (tmp == 3)
				Z[e->t] = 1;
			Queue[Tail ++] = e->t;
			Rec(e->t);
			Known[e->t] = 1;
		}
		while (Head < Tail)
		{
			int Cur = Queue[Head];
			++ Head;
			for (TEdge *e = Adj[Cur]; e; e = e->n)
				if (!Known[e->t])
				{
					if (Deg[Cur] == 4 && Deg[e->t] <= 4 && OnlyOne(Cur)) {
						GoDirect(e->t, Cur);
						Queue[Tail ++] = e->t;
						Rec(e->t);
						Known[e->t] = 1;
					} else if (CanKnow(e->t)) {
						Know(e->t);
						Queue[Tail ++] = e->t;
						Rec(e->t);
						Known[e->t] = 1;
					}
				}
		}
	}
	
	bool CompareXYZ(int id1, int id2) {
		return make_pair(make_pair(X[id1], Y[id1]), Z[id1]) < make_pair(make_pair(X[id2], Y[id2]), Z[id2]);
	}
	
	bool CompareX(int i, int j) {
		return X[LightID[i]] < X[LightID[j]];
	}
	
	bool CompareY(int i, int j) {
		return Y[LightID[i]] < Y[LightID[j]];
	}
	
	bool CompareZ(int i, int j) {
		return Z[LightID[i]] < Z[LightID[j]];
	}
	
	inline int Lowbit(const int x) {
		return x & (- x);
	}
	
	void DFS(int Step, int State[], int Score) {
		if (Step == N) {
			int mask = 0;
			for (int i = 0; i < N; ++ i)
				if (State[i] == 4)
					mask |= (1 << i);
			int DeltaMin = 0, DeltaMax = 0;
			for (int i = 0; i < NXYGroup; ++ i)
				if (mask & XYGroup[i]) {
					int Sum = 0, Max = 0;
					int l = 0, r = A - 1;
					int g = (mask & XYGroup[i]);
					int x = X[LightID[__builtin_ctz(g)]], y = Y[LightID[__builtin_ctz(g)]];
					int t = 0;
					for (; g != 0; g ^= Lowbit(g)) {
						int k = __builtin_ctz(g);
						r = Z[LightID[k]];
						int tmp = ZSum[x][y][l] - ZSum[x][y][r];
						for (; t < N && Z[LightID[ZSorted[N][t]]] <= r; ++ t) {
							int z = Z[LightID[ZSorted[N][t]]];
							if (State[ZSorted[N][t]] < 4 && z >= l) {
								if ((((State[ZSorted[N][t]] == 0 && x < X[LightID[ZSorted[N][t]]]) || (State[ZSorted[N][t]] == 1 && x > X[LightID[ZSorted[N][t]]])) && Y[LightID[ZSorted[N][t]]] == y) || (((State[ZSorted[N][t]] == 2 && y < Y[LightID[ZSorted[N][t]]]) || (State[ZSorted[N][t]] == 3 && y > Y[LightID[ZSorted[N][t]]])) && X[LightID[ZSorted[N][t]]] == x)) {
									tmp -= Beauty[x][y][z];
									while (t + 1 < N && Z[LightID[ZSorted[N][t + 1]]] == z)
										++ t;
								}
							}
						}
						Sum += tmp;
						checkmax(Max, tmp);
						l = r;
					}
					r = A;
					int tmp = ZSum[x][y][l] - ZSum[x][y][r];
					for (; t < N && Z[LightID[ZSorted[N][t]]] <= r; ++ t) {
						int z = Z[LightID[ZSorted[N][t]]];
						if (State[ZSorted[N][t]] < 4 && z >= l) {
							if ((((State[ZSorted[N][t]] == 0 && x < X[LightID[ZSorted[N][t]]]) || (State[ZSorted[N][t]] == 1 && x > X[LightID[ZSorted[N][t]]])) && Y[LightID[ZSorted[N][t]]] == y) || (((State[ZSorted[N][t]] == 2 && y < Y[LightID[ZSorted[N][t]]]) || (State[ZSorted[N][t]] == 3 && y > Y[LightID[ZSorted[N][t]]])) && X[LightID[ZSorted[N][t]]] == x)) {
								tmp -= Beauty[x][y][z];
								while (t + 1 < N && Z[LightID[ZSorted[N][t + 1]]] == z)
									++ t;
							}
						}
					}
					Sum += tmp;
					checkmax(Max, tmp);
					DeltaMin += Sum - Max;
					if (__builtin_popcount(mask & XYGroup[i]) == 1)
						DeltaMax += Max;
					else
						DeltaMax += Sum;
				}
			checkmin(Ans1, Score + DeltaMin);
			checkmax(Ans2, Score + DeltaMax);
			return;
		}
		int Delta = 0, l, r;
		State[Step] = 0; // < x, y, z
		l = 0, r = X[LightID[Step]];
		for (int k = 0; k < Step; ++ k) {
			if ((State[k] == 0 || State[k] == 1) && Y[LightID[k]] == Y[LightID[Step]] && Z[LightID[k]] == Z[LightID[Step]]) {
				if (State[k] == 0)
					checkmax(l, X[LightID[k]]);
				else
					checkmin(r, X[LightID[k]]);
			}
		}
		if (l <= r) {
			Delta = XSum[l][Y[LightID[Step]]][Z[LightID[Step]]] - XSum[r + 1][Y[LightID[Step]]][Z[LightID[Step]]];
			for (int j = 0; j < Step && l <= r; ++ j) {
				int k = XSorted[Step][j];
				if (X[LightID[k]] > r)
					break;
				if (((State[k] == 2 && Y[LightID[Step]] < Y[LightID[k]]) || (State[k] == 3 && Y[LightID[Step]] > Y[LightID[k]])) && X[LightID[k]] >= l && Z[LightID[k]] == Z[LightID[Step]]) {
					Delta -= Beauty[X[LightID[k]]][Y[LightID[Step]]][Z[LightID[Step]]];
					l = X[LightID[k]] + 1;
				}
			}
		}
		DFS(Step + 1, State, Score + Delta);
		
		State[Step] = 1; // > x, y, z
		Delta = 0;
		l = X[LightID[Step]], r = A - 1;
		for (int k = 0; k < Step; ++ k) {
			if ((State[k] == 0 || State[k] == 1) && Y[LightID[k]] == Y[LightID[Step]] && Z[LightID[k]] == Z[LightID[Step]]) {
				if (State[k] == 0)
					checkmax(l, X[LightID[k]]);
				else
					checkmin(r, X[LightID[k]]);
			}
		}
		if (l <= r) {
			Delta = XSum[l][Y[LightID[Step]]][Z[LightID[Step]]] - XSum[r + 1][Y[LightID[Step]]][Z[LightID[Step]]];
			for (int j = 0; j < Step && l <= r; ++ j) {
				int k = XSorted[Step][j];
				if (X[LightID[k]] > r)
					break;
				if (((State[k] == 2 && Y[LightID[Step]] < Y[LightID[k]]) || (State[k] == 3 && Y[LightID[Step]] > Y[LightID[k]])) && X[LightID[k]] >= l && Z[LightID[k]] == Z[LightID[Step]]) {
					Delta -= Beauty[X[LightID[k]]][Y[LightID[Step]]][Z[LightID[Step]]];
					l = X[LightID[k]] + 1;
				}
			}
		}
		DFS(Step + 1, State, Score + Delta);
		
		State[Step] = 2; // x, < y, z
		Delta = 0;
		l = 0, r = Y[LightID[Step]];
		for (int k = 0; k < Step; ++ k) {
			if ((State[k] == 2 || State[k] == 3) && X[LightID[k]] == X[LightID[Step]] && Z[LightID[k]] == Z[LightID[Step]]) {
				if (State[k] == 2)
					checkmax(l, Y[LightID[k]]);
				else
					checkmin(r, Y[LightID[k]]);
			}
		}
		if (l <= r) {
			Delta = YSum[X[LightID[Step]]][l][Z[LightID[Step]]] - YSum[X[LightID[Step]]][r + 1][Z[LightID[Step]]];
			for (int j = 0; j < Step && l <= r; ++ j) {
				int k = YSorted[Step][j];
				if (Y[LightID[k]] > r)
					break;
				if (((State[k] == 0 && X[LightID[Step]] < X[LightID[k]]) || (State[k] == 1 && X[LightID[Step]] > X[LightID[k]])) && Y[LightID[k]] >= l && Z[LightID[k]] == Z[LightID[Step]]) {
					Delta -= Beauty[X[LightID[Step]]][Y[LightID[k]]][Z[LightID[Step]]];
					l = Y[LightID[k]] + 1;
				}
			}
		}
		DFS(Step + 1, State, Score + Delta);
		
		State[Step] = 3; // x, > y, z
		Delta = 0;
		l = Y[LightID[Step]], r = A - 1;
		for (int k = 0; k < Step; ++ k) {
			if ((State[k] == 2 || State[k] == 3) && X[LightID[k]] == X[LightID[Step]] && Z[LightID[k]] == Z[LightID[Step]]) {
				if (State[k] == 2)
					checkmax(l, Y[LightID[k]]);
				else
					checkmin(r, Y[LightID[k]]);
			}
		}
		if (l <= r) {
			Delta = YSum[X[LightID[Step]]][l][Z[LightID[Step]]] - YSum[X[LightID[Step]]][r + 1][Z[LightID[Step]]];
			for (int j = 0; j < Step && l <= r; ++ j) {
				int k = YSorted[Step][j];
				if (Y[LightID[k]] > r)
					break;
				if (((State[k] == 0 && X[LightID[Step]] < X[LightID[k]]) || (State[k] == 1 && X[LightID[Step]] > X[LightID[k]])) && Y[LightID[k]] >= l && Z[LightID[k]] == Z[LightID[Step]]) {
					Delta -= Beauty[X[LightID[Step]]][Y[LightID[k]]][Z[LightID[Step]]];
					l = Y[LightID[k]] + 1;
				}
			}
		}
		DFS(Step + 1, State, Score + Delta);
		
		State[Step] = 4; // x, y, ? z
		DFS(Step + 1, State, Score);
	}
	
	void Work() {
		N = 0;
		for (int i = 1; i <= A * A * A; ++ i) {
			if (Value[i] == 0)
				LightID[N ++] = i;
			Beauty[X[i]][Y[i]][Z[i]] = Value[i];
		}
		for (int i = 0; i < A; ++ i)
			for (int j = 0; j < A; ++ j)
				XSum[A][i][j] = YSum[i][A][j] = ZSum[i][j][A] = 0;
		for (int i = A - 1; i >= 0; -- i)
			for (int j = A - 1; j >= 0; -- j)
				for (int k = A - 1; k >= 0; -- k) {
					XSum[i][j][k] = XSum[i + 1][j][k] + Beauty[i][j][k];
					YSum[i][j][k] = YSum[i][j + 1][k] + Beauty[i][j][k];
					ZSum[i][j][k] = ZSum[i][j][k + 1] + Beauty[i][j][k];
				}
		sort(LightID, LightID + N, CompareXYZ);
		NXYGroup = 0;
		for (int mask = (1 << N) - 1; mask != 0; ++ NXYGroup) {
			for (int j = 0; j < N; ++ j)
				if ((mask >> j) & 1) {
					XYGroup[NXYGroup] = (1 << j);
					for (int k = j + 1; k < N; ++ k)
						if (X[LightID[j]] == X[LightID[k]] && Y[LightID[j]] == Y[LightID[k]])
							XYGroup[NXYGroup] |= (1 << k);
					mask ^= XYGroup[NXYGroup];
					break;
				}
		}
		for (int i = 0; i <= N; ++ i) {
			for (int j = 0; j < i; ++ j)
				XSorted[i][j] = YSorted[i][j] = ZSorted[i][j] = j;
			sort(XSorted[i], XSorted[i] + i, CompareX);
			sort(YSorted[i], YSorted[i] + i, CompareY);
			sort(ZSorted[i], ZSorted[i] + i, CompareZ);
		}
		int State[MaxiN];
		Ans1 = INT_MAX;
		Ans2 = INT_MIN;
		DFS(0, State, 0);
	}
	
	void Run(FILE *fi, FILE *fo) {
		Import(fi);
		Do();
		Work();
		Export(fo);
	}
}

namespace DataMaker {
	const int MaxiA = 82;
	const int MaxiN = 12;
	
	int A, N, Ans1, Ans2, NHash;
	int LX[MaxiN], LY[MaxiN], LZ[MaxiN];
	int State[MaxiN];
	int ID[MaxiA][MaxiA][MaxiA], G[MaxiA][MaxiA][MaxiA], S[MaxiA][MaxiA][MaxiA], Hash[MaxiA][MaxiA][MaxiA];
	int Value[MaxiA * MaxiA * MaxiA];
	vector <int> Adj[MaxiA * MaxiA * MaxiA];
	
	bool InRange(int x) {
		return 0 <= x && x < A;
	}
	
	bool InRange(int x, int y, int z) {
		return InRange(x) && InRange(y) && InRange(z);
	}
	
	int Sum(int x1, int y1, int z1, int x2, int y2, int z2) {
		if (x1 > x2)
			swap(x1, x2);
		if (y1 > y2)
			swap(y1, y2);
		if (z1 > z2)
			swap(z1, z2);
		++ x2, ++ y2, ++ z2;
		return S[x2][y2][z2] - S[x1][y2][z2] - S[x2][y1][z2] - S[x2][y2][z1] + S[x1][y1][z2] + S[x1][y2][z1] + S[x2][y1][z1] - S[x1][y1][z1];
	}
	
	void DFS(int k, int score) {
		if (k == N) {
			checkmin(Ans1, score);
			checkmax(Ans2, score);
			return;
		}
		int delta, l, r;
		State[k] = 0;
		delta = 0;
		l = 0, r = LX[k] - 1;
		for (int i = 0; i < k; ++ i)
			if (LY[i] == LY[k] && LZ[i] == LZ[k]) {
				if (State[i] == 0)
					checkmax(l, LX[i] + 1);
				if (State[i] == 1)
					checkmin(r, LX[i] - 1);
			}
		if (l <= r) {
			delta += Sum(l, LY[k], LZ[k], r, LY[k], LZ[k]);
			++ NHash;
			for (int i = 0; i < k; ++ i)
				if (Hash[LX[i]][LY[k]][LZ[k]] != NHash && LX[i] >= l && LX[i] <= r && ((State[i] == 2 && LY[k] < LY[i] && LZ[k] == LZ[i]) || (State[i] == 3 && LY[k] > LY[i] && LZ[k] == LZ[i]) || (State[i] == 4 && LY[k] == LY[i] && LZ[k] < LZ[i]) || (State[i] == 5 && LY[k] == LY[i] && LZ[k] > LZ[i]))) {
					Hash[LX[i]][LY[k]][LZ[k]] = NHash;
					delta -= G[LX[i]][LY[k]][LZ[k]];
				}
		}
		DFS(k + 1, score + delta);
		State[k] = 1;
		delta = 0;
		l = LX[k] + 1, r = A - 1;
		for (int i = 0; i < k; ++ i)
			if (LY[i] == LY[k] && LZ[i] == LZ[k]) {
				if (State[i] == 0)
					checkmax(l, LX[i] + 1);
				if (State[i] == 1)
					checkmin(r, LX[i] - 1);
			}
		if (l <= r) {
			delta += Sum(l, LY[k], LZ[k], r, LY[k], LZ[k]);
			++ NHash;
			for (int i = 0; i < k; ++ i)
				if (Hash[LX[i]][LY[k]][LZ[k]] != NHash && LX[i] >= l && LX[i] <= r && ((State[i] == 2 && LY[k] < LY[i] && LZ[k] == LZ[i]) || (State[i] == 3 && LY[k] > LY[i] && LZ[k] == LZ[i]) || (State[i] == 4 && LY[k] == LY[i] && LZ[k] < LZ[i]) || (State[i] == 5 && LY[k] == LY[i] && LZ[k] > LZ[i]))) {
					Hash[LX[i]][LY[k]][LZ[k]] = NHash;
					delta -= G[LX[i]][LY[k]][LZ[k]];
				}
		}
		DFS(k + 1, score + delta);
		State[k] = 2;
		delta = 0;
		l = 0, r = LY[k] - 1;
		for (int i = 0; i < k; ++ i)
			if (LX[i] == LX[k] && LZ[i] == LZ[k]) {
				if (State[i] == 2)
					checkmax(l, LY[i] + 1);
				if (State[i] == 3)
					checkmin(r, LY[i] - 1);
			}
		if (l <= r) {
			delta += Sum(LX[k], l, LZ[k], LX[k], r, LZ[k]);
			++ NHash;
			for (int i = 0; i < k; ++ i)
				if (Hash[LX[k]][LY[i]][LZ[k]] != NHash && LY[i] >= l && LY[i] <= r && ((State[i] == 0 && LX[k] < LX[i] && LZ[k] == LZ[i]) || (State[i] == 1 && LX[k] > LX[i] && LZ[k] == LZ[i]) || (State[i] == 4 && LX[k] == LX[i] && LZ[k] < LZ[i]) || (State[i] == 5 && LX[k] == LX[i] && LZ[k] > LZ[i]))) {
					Hash[LX[k]][LY[i]][LZ[k]] = NHash;
					delta -= G[LX[k]][LY[i]][LZ[k]];
				}
		}
		DFS(k + 1, score + delta);
		State[k] = 3;
		delta = 0;
		l = LY[k] + 1, r = A - 1;
		for (int i = 0; i < k; ++ i)
			if (LX[i] == LX[k] && LZ[i] == LZ[k]) {
				if (State[i] == 2)
					checkmax(l, LY[i] + 1);
				if (State[i] == 3)
					checkmin(r, LY[i] - 1);
			}
		if (l <= r) {
			delta += Sum(LX[k], l, LZ[k], LX[k], r, LZ[k]);
			++ NHash;
			for (int i = 0; i < k; ++ i)
				if (Hash[LX[k]][LY[i]][LZ[k]] != NHash && LY[i] >= l && LY[i] <= r && ((State[i] == 0 && LX[k] < LX[i] && LZ[k] == LZ[i]) || (State[i] == 1 && LX[k] > LX[i] && LZ[k] == LZ[i]) || (State[i] == 4 && LX[k] == LX[i] && LZ[k] < LZ[i]) || (State[i] == 5 && LX[k] == LX[i] && LZ[k] > LZ[i]))) {
					Hash[LX[k]][LY[i]][LZ[k]] = NHash;
					delta -= G[LX[k]][LY[i]][LZ[k]];
				}
		}
		DFS(k + 1, score + delta);
		State[k] = 4;
		delta = 0;
		l = 0, r = LZ[k] - 1;
		for (int i = 0; i < k; ++ i)
			if (LX[i] == LX[k] && LY[i] == LY[k]) {
				if (State[i] == 4)
					checkmax(l, LZ[i] + 1);
				if (State[i] == 5)
					checkmin(r, LZ[i] - 1);
			}
		if (l <= r) {
			delta += Sum(LX[k], LY[k], l, LX[k], LY[k], r);
			++ NHash;
			for (int i = 0; i < k; ++ i)
				if (Hash[LX[k]][LY[k]][LZ[i]] != NHash && LZ[i] >= l && LZ[i] <= r && ((State[i] == 0 && LX[k] < LX[i] && LY[k] == LY[i]) || (State[i] == 1 && LX[k] > LX[i] && LY[k] == LY[i]) || (State[i] == 2 && LX[k] == LX[i] && LY[k] < LY[i]) || (State[i] == 3 && LX[k] == LX[i] && LY[k] > LY[i]))) {
					Hash[LX[k]][LY[k]][LZ[i]] = NHash;
					delta -= G[LX[k]][LY[k]][LZ[i]];
				}
		}
		DFS(k + 1, score + delta);
		State[k] = 5;
		delta = 0;
		l = LZ[k] + 1, r = A - 1;
		for (int i = 0; i < k; ++ i)
			if (LX[i] == LX[k] && LY[i] == LY[k]) {
				if (State[i] == 4)
					checkmax(l, LZ[i] + 1);
				if (State[i] == 5)
					checkmin(r, LZ[i] - 1);
			}
		if (l <= r) {
			delta += Sum(LX[k], LY[k], l, LX[k], LY[k], r);
			++ NHash;
			for (int i = 0; i < k; ++ i)
				if (Hash[LX[k]][LY[k]][LZ[i]] != NHash && LZ[i] >= l && LZ[i] <= r && ((State[i] == 0 && LX[k] < LX[i] && LY[k] == LY[i]) || (State[i] == 1 && LX[k] > LX[i] && LY[k] == LY[i]) || (State[i] == 2 && LX[k] == LX[i] && LY[k] < LY[i]) || (State[i] == 3 && LX[k] == LX[i] && LY[k] > LY[i]))) {
					Hash[LX[k]][LY[k]][LZ[i]] = NHash;
					delta -= G[LX[k]][LY[k]][LZ[i]];
				}
		}
		DFS(k + 1, score + delta);
	}
	
	void Generate(FILE *fi, FILE *fo) {
		for (int i = 0; i < A; ++ i)
			for (int j = 0; j < A; ++ j)
				for (int k = 0; k < A; ++ k)
					G[i][j][k] = rand() % 999999 + 1;
		
		int T = round(sqrt(N + 1)) + rand() % 2;
		vector <int> XC, YC, ZC;
		XC.clear(), YC.clear(), ZC.clear();
		
		for (int i = 0; i < T; ++ i) {
			if (A > 2 && i == 0) {
				XC.push_back(rand() % (A - 2) + 1);
				YC.push_back(rand() % (A - 2) + 1);
				ZC.push_back(rand() % (A - 2) + 1);
			} else {
				XC.push_back(rand() % A);
				YC.push_back(rand() % A);
				ZC.push_back(rand() % A);
			}
		}
		
		for (int i = 0; i < N; ++ i) {
			int a = rand() % T;
			int b = rand() % T;
			int c = rand() % T;
			while (G[XC[a]][YC[b]][ZC[c]] == 0) {
				a = rand() % T;
				b = rand() % T;
				c = rand() % T;
			}
			G[XC[a]][YC[b]][ZC[c]] = 0;
			LX[i] = XC[a], LY[i] = YC[b], LZ[i] = ZC[c];
		}
		
		memset(S, 0, sizeof(S));
		for (int i = 0; i < A; ++ i)
			for (int j = 0; j < A; ++ j)
				for (int k = 0; k < A; ++ k)
					S[i + 1][j + 1][k + 1] = G[i][j][k] + S[i][j + 1][k + 1] + S[i + 1][j][k + 1] + S[i + 1][j + 1][k] - S[i][j][k + 1] - S[i][j + 1][k] - S[i + 1][j][k] + S[i][j][k];
		
		Ans1 = INT_MAX;
		Ans2 = INT_MIN;
		DFS(0, 0);
		
		vector <int> Seq;
		Seq.resize(A * A * A);
		for (int i = 0; i < A * A * A; ++ i)
			Seq[i] = i + 1;
		random_shuffle(Seq.begin(), Seq.end());
		for (int i = 0; i < A * A * A; ++ i) {
			int x = i / (A * A);
			int y = (i / A) % A;
			int z = i % A;
			ID[x][y][z] = Seq[i];
		}
		Seq.clear();
		for (int i = 0; i < A; ++ i)
			for (int j = 0; j < A; ++ j)
				for (int k = 0; k < A; ++ k) {
					Adj[ID[i][j][k]].clear();
					Value[ID[i][j][k]] = G[i][j][k];
					for (int a = - 1; a <= 1; ++ a)
						for (int b = - 1; b <= 1; ++ b)
							for (int c = - 1; c <= 1; ++ c)
								if (abs(a) + abs(b) + abs(c) == 1 && InRange(i + a, j + b, k + c))
									Adj[ID[i][j][k]].push_back(ID[i + a][j + b][k + c]);
				}
		
		fprintf(fi, "%d\n", A);
		for (int i = 1; i <= A * A * A; ++ i) {
			fprintf(fi, "%d", Value[i]);
			random_shuffle(Adj[i].begin(), Adj[i].end());
			for (int j = 0; j < (int) Adj[i].size(); ++ j)
				fprintf(fi, " %d", Adj[i][j]);
			fprintf(fi, "\n");
		}
		fprintf(fo, "%d %d\n", Ans1, Ans2);
	}
	
	void Run() {
		srand(2048); // the name of the 1st problem.
		FILE *fs = fopen("Default.in", "r");
		int TestCase;
		fscanf(fs, "%d", &TestCase);
		for (int i = 1; i <= TestCase; ++ i) {
			cerr << "processing case " << i << endl;
			fscanf(fs, "%d%d", &A, &N);
			char If[20], Of[20];
			sprintf(If, "glitter%d.in", i);
			sprintf(Of, "glitter%d.ans", i);
			
			FILE *fp = fopen(If, "w");
			FILE *fq = fopen(Of, "w");
			
			Generate(fp, fq);
			
			fclose(fp);
			fclose(fq);
		}
		fclose(fs);
	}
}

int main(int argc, char **argv) {
	if (argc == 1) {
		FILE *fp = fopen("glitter.in", "r");
		FILE *fq = fopen("glitter.out", "w");
		Poor::Run(fp, fq);
		fclose(fp);
		fclose(fq);
	} else if (argc == 2 && strcmp(argv[1], "--md") == 0) {
		DataMaker::Run();
	} else if (argc == 3) {
		FILE *fp = fopen(argv[1], "r");
		FILE *fq = fopen(argv[2], "w");
		Poor::Run(fp, fq);
		fclose(fp);
		fclose(fq);
	}
	return 0;
}
 
      这道题目恶心之处在于公式的推导,这里简单讲一下公式的推导。假设直线是y=kx+b,点(xi,yi)到直线的距离就是[tex]\frac{|k*xi-yi+b|}{\sqrt{k^2+1}}[/tex],只要有点数学基础大概都知道这个公式。然后我们将其平方,再把所有式子加起来,然后用k表示b,我们会发现得到了一个很简单的式子[tex]b=\overline{y}-k*\overline{x}[/tex],[tex]\overline{x}[/tex]表示x的平均数,再将b代回原式,我们就得到了一个与k有关的复杂式子[tex]\frac{A*k^2+B*k+C}{k^2+1}[/tex],我对这个式子进行了求导,最后得出[tex]B*k^2-2*(A-C)*k-B=0[/tex]的关系,用公式求出k的值再求出整个式子的值。但是,当B=0的时候,就无法通过该方法求解了,这个时候的答案就是A(我也不知道为什么,是根据数据猜出来的)。这道题另一个比较恶心的地方在于环接外向树,一般的做法好像是分类讨论,我这里有一种用时间来换取编程复杂度的方法,在dfs的时候,将环上的一条边去掉,这样就变成了树上的问题。假设去掉的边两端分别是p1和p2,查询的时候,对于x和y两个点,需要查询(x,y)、(x,p1)+(y,p2)或(x,p2)+(y,p1),取最小的那个答案就行。
//链剖+环接外向树
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
typedef double D;
const int N=200010;
const int M=1000010;
const D eps=1e-6;
int n,m,q,a[N],b[N],p1,p2;
int g[N],to[N<<1],nxt[N<<1],tot;
int pos[N],dfn[N],df,w[N];
int d[N],top[N],fa[N],num[N];
int c1[M],c2[M],c3[M],c4[M],c5[M];
int s1,s2,s3,s4,s5;
bool ok[N],vis[N],loop,f;
void read(int &a) {
    char ch; while (!(((ch=getchar())>='0'&&ch<='9')||(ch=='-')));
    if (ch=='-') f=1,a=0;else f=0,a=ch-'0';
    while ((ch=getchar())>='0'&&ch<='9') (a*=10)+=ch-'0';
    if (f) a=-a;
}
void addedge(int x,int y) {
    to[++tot]=y; nxt[tot]=g[x]; g[x]=tot;
    to[++tot]=x; nxt[tot]=g[y]; g[y]=tot;
}
void dfs(int x,int fat) {
    vis[x]=true; fa[x]=fat;
    for (int k=g[x];k;k=nxt[k]) {
        if (to[k]==fat) continue;
        if (ok[k]) continue;
        if (vis[to[k]]) {
            p1=x; p2=to[k];
            ok[k]=loop=true;
            continue;
        } dfs(to[k],x);
        if (num[to[k]]>num[w[x]]) w[x]=to[k];
        num[x]+=num[to[k]];
    } num[x]++;
}
void dfs2(int x,int dep,int tail) {
    dfn[x]=++df; pos[df]=x;
    top[x]=tail; d[x]=dep;
    if (w[x]) dfs2(w[x],dep+1,tail);
    for (int k=g[x];k;k=nxt[k]) {
        if (to[k]==fa[x]) continue;
        if (to[k]==w[x]) continue;
        if (ok[k]) continue;
        dfs2(to[k],dep+1,to[k]);
    }
}
void build(int i,int l,int r) {
    if (l==r) {
        c1[i]=a[pos[l]];
        c2[i]=b[pos[l]];
        c3[i]=a[pos[l]]*b[pos[l]];
        c4[i]=a[pos[l]]*a[pos[l]];
        c5[i]=b[pos[l]]*b[pos[l]];
        return;
    } int mid=(l+r)>>1;
    build(i<<1,l,mid);
    build(i<<1|1,mid+1,r);
    c1[i]=c1[i<<1]+c1[i<<1|1];
    c2[i]=c2[i<<1]+c2[i<<1|1];
    c3[i]=c3[i<<1]+c3[i<<1|1];
    c4[i]=c4[i<<1]+c4[i<<1|1];
    c5[i]=c5[i<<1]+c5[i<<1|1];
}
void ask(int i,int l,int r,int x,int y) {
    if (x<=l&&y>=r) {
        s1+=c1[i];
        s2+=c2[i];
        s3+=c3[i];
        s4+=c4[i];
        s5+=c5[i];
        return;
    } int mid=(l+r)>>1;
    if (x<=mid) ask(i<<1,l,mid,x,y);
    if (y>mid) ask(i<<1|1,mid+1,r,x,y);
}
int LCA(int x,int y) {
    while (top[x]!=top[y]) {
        if (d[top[x]]>d[top[y]]) x=fa[top[x]];
        else y=fa[top[y]];
    } return d[x]<d[y]?x:y;
}
void query(int x,int y) {
    while (top[x]!=top[y]) {
        if (d[top[x]]>d[top[y]]) ask(1,1,n,dfn[top[x]],dfn[x]),x=fa[top[x]];
        else ask(1,1,n,dfn[top[y]],dfn[y]),y=fa[top[y]];
    }
    if (d[x]<d[y]) ask(1,1,n,dfn[x],dfn[y]);
    else ask(1,1,n,dfn[y],dfn[x]);
}
// c1=s1=sigma(x[i])  c2=s2=sigma(y[i])
// c3=s3=sigma(x[i]*y[i])
// c4=s4=sigma(x[i]*x[i])
// c5=s5=sigma(y[i]*y[i])
D A,B,C,K,bx,by,tmp,ans;
int cnt,z;
D sqr(D x) {return x*x;}
bool sgn(D x) {return fabs(x)<eps?0:1;}
void calc() {
    bx=(D)s1/cnt; by=(D)s2/cnt;
    A=s4+cnt*bx*bx-2*bx*s1;
    B=-2*cnt*bx*by-2*s3+2*s2*bx+2*by*s1;
    C=s5+cnt*by*by-2*by*s2;
    if (sgn(B)) {
        K=(2*(A-C)-sqrt(4*(A-C)*(A-C)+4*B*B))/(2*B);
        tmp=(A*K*K+B*K+C)/(K*K+1.0);
    } else tmp=A;
    if (tmp<ans) ans=tmp;
}
void calc1(int x,int y) {
    s1=s2=s3=s4=s5=0;
    query(x,y);
    z=LCA(x,y);
    cnt=d[y]-d[z]+d[x]-d[z]+1;
    calc();
}
void calc2(int x,int y) {
    s1=s2=s3=s4=s5=cnt=0;
    query(x,p1); query(y,p2);
    z=LCA(x,p1); cnt+=d[x]-d[z]+d[p1]-d[z]+1;
    z=LCA(y,p2); cnt+=d[y]-d[z]+d[p2]-d[z]+1;
    calc(); s1=s2=s3=s4=s5=cnt=0;
    query(x,p2); query(y,p1);
    z=LCA(x,p2); cnt+=d[x]-d[z]+d[p2]-d[z]+1;
    z=LCA(y,p1); cnt+=d[y]-d[z]+d[p1]-d[z]+1;
    calc();
}
int main() {
    int i,x,y;
    read(n); read(m);
    for (i=1;i<=n;i++) read(a[i]),read(b[i]);
    for (i=1;i<=m;i++) {
        read(x); read(y);
        addedge(x,y);
    } dfs(1,0);
    dfs2(1,1,1);
    build(1,1,n);
    read(q);
    while (q--) {
        read(x); read(y);
        ans=1000000000.0;
        if (x==y) {puts("0.00000");continue;}
        calc1(x,y);
        if (loop) calc2(x,y);
        printf("%.5f\n",ans+eps);
    }
    return 0;
}
 
      好久没有碰上要用莫队的题目了,结果现在连莫队都不会打了。先是看了一遍COT2的程序,然后明白了树上莫队该怎么搞。码完代码后死活AC不了,然后打开了数颜色的代码,结果发现TMD带修改莫队打错了,改来改去最后总算是AC了。具体搞法就不说了,大家应该都懂。
//树上莫队+带修改莫队
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
typedef long long ll;
typedef double D;
const int N=300010;
struct node{int x,y,z,t;}op[N],p[N];
int n,m,q,tn,v[N],w[N],c[N],b[N],f[N];
int fa[N],d[N],g[N],to[N],nxt[N],tot;
int point[N],dfn[N],top[N],s[N],num[N];
int vis[N],seq[N],st[N],ed[N],len,df;
int pos[N],b_cnt,op_cnt,p_cnt,sz;
int indexl,indexr,indext,rnd;
ll ans[N],tmp;
bool ok[N];
bool cmp(const node &a,const node &b) {return pos[a.x]<pos[b.x]||(pos[a.x]==pos[b.x]&&pos[a.y]<pos[b.y])||(pos[a.x]==pos[b.x]&&pos[a.y]==pos[b.y]&&a.t<b.t);}
void read(int &a) {
    char ch; while (!((ch=getchar())>='0'&&ch<='9'));
    a=ch-'0'; while ((ch=getchar())>='0'&&ch<='9') (a*=10)+=ch-'0';
}
void addedge(int x,int y) {
    to[++tot]=y; nxt[tot]=g[x]; g[x]=tot;
    to[++tot]=x; nxt[tot]=g[y]; g[y]=tot;
}
void dfs(int x,int fat) {
    fa[x]=fat;
    for (int k=g[x];k;k=nxt[k]) {
        if (to[k]==fat) continue;
        dfs(to[k],x);
        if (num[to[k]]>num[s[x]]) s[x]=to[k];
        num[x]+=num[to[k]];
    } num[x]++;
}
void dfs(int x,int dep,int tail) {
    top[x]=tail; d[x]=dep;
    seq[st[x]=++len]=dfn[x]=++df;
    point[dfn[x]]=x;
    if (s[x]) dfs(s[x],dep+1,tail);
    for (int k=g[x];k;k=nxt[k]) {
        if (to[k]==fa[x]) continue;
        if (to[k]==s[x]) continue;
        dfs(to[k],dep+1,to[k]);
    } seq[ed[x]=++len]=dfn[x];
}
int LCA(int x,int y) {
    while (top[x]!=top[y]) {
        if (d[top[x]]>d[top[y]]) x=fa[top[x]];
        else y=fa[top[y]];
    } return d[x]<d[y]?x:y;
}
void init() {
    int i,k,x,y,z;
    read(n); read(m); read(q);
    for (i=1;i<=m;i++) read(v[i]);
    for (i=1;i<=n;i++) read(w[i]);
    for (i=1;i<n;i++) {
        read(x); read(y);
        addedge(x,y);
    } tn=n<<1|1; dfs(1,0); dfs(1,1,1);
    for (i=1;i<=n;i++) read(c[i]);
    for (i=1;i<=q;i++) {
        read(k); read(x); read(y);
        if (k==0) {
            op_cnt++;
            op[op_cnt].x=x;
            op[op_cnt].y=y;
            op[op_cnt].t=i;
        } else if (k==1) {
            if (st[x]>st[y]) swap(x,y);
            ok[p[++p_cnt].t=i]=true;
            z=LCA(x,y);
            if (z==x) {
                p[p_cnt].x=st[x];
                p[p_cnt].y=st[y];
            } else {
                p[p_cnt].z=z;
                p[p_cnt].x=ed[x];
                p[p_cnt].y=st[y];
            }
        }
    } sz=(int)pow(n*2,(D)2/3);
    for (i=1;i<=tn;i++) {
        if ((i-1)%sz==0) b_cnt++;
        pos[i]=b_cnt;
    } sort(p+1,p+1+p_cnt,cmp);
}
void work() {
    int i,j,x;
    for (i=1;i<=p_cnt;i++) {
        if (pos[p[i].x]!=pos[p[i-1].x]) {
            indext=1; rnd++; tmp=0;
            memcpy(b,c,(n+1)*sizeof(int));
            memset(f,0,(m+1)*sizeof(int));
            indexl=p[i].x; indexr=p[i].x-1;
        } else if (pos[p[i].y]!=pos[p[i-1].y]) {
            for (j=1;j<=n;j++) {
                if (b[j]==c[j]) continue;
                if (vis[dfn[j]]==rnd) {
                    tmp-=(ll)w[f[b[j]]--]*v[b[j]];
                    tmp+=(ll)w[++f[c[j]]]*v[c[j]];
                } b[j]=c[j];
            } indext=1;
        }
        while (indext<=op_cnt&&op[indext].t<=p[i].t) {
            if (vis[dfn[op[indext].x]]==rnd) {
                x=b[op[indext].x];
                tmp-=(ll)w[f[x]--]*v[x];
                x=b[op[indext].x]=op[indext].y;
                tmp+=(ll)w[++f[x]]*v[x];
            } else b[op[indext].x]=op[indext].y;
            indext++;
        }
        while (indexr<p[i].y) {
            x=b[point[seq[++indexr]]];
            if (vis[seq[indexr]]==rnd) {
                tmp-=(ll)w[f[x]--]*v[x];
                vis[seq[indexr]]=0;
            } else {
                tmp+=(ll)w[++f[x]]*v[x];
                vis[seq[indexr]]=rnd;
            }
        }
        while (indexr>p[i].y) {
            x=b[point[seq[indexr]]];
            if (vis[seq[indexr]]==rnd) {
                tmp-=(ll)w[f[x]--]*v[x];
                vis[seq[indexr]]=0;
            } else {
                tmp+=(ll)w[++f[x]]*v[x];
                vis[seq[indexr]]=rnd;
            } indexr--;
        }
        while (indexl>p[i].x) {
            x=b[point[seq[--indexl]]];
            if (vis[seq[indexl]]==rnd) {
                tmp-=(ll)w[f[x]--]*v[x];
                vis[seq[indexl]]=0;
            } else {
                tmp+=(ll)w[++f[x]]*v[x];
                vis[seq[indexl]]=rnd;
            }
        }
        while (indexl<p[i].x) {
            x=b[point[seq[indexl]]];
            if (vis[seq[indexl]]==rnd) {
                tmp-=(ll)w[f[x]--]*v[x];
                vis[seq[indexl]]=0;
            } else {
                tmp+=(ll)w[++f[x]]*v[x];
                vis[seq[indexl]]=rnd;
            } indexl++;
        }
        if (!p[i].z) ans[p[i].t]=tmp;
        else ans[p[i].t]=tmp+(ll)w[f[b[p[i].z]]+1]*v[b[p[i].z]];
    } for (i=1;i<=q;i++) if (ok[i]) printf("%lld\n",ans[i]);
}
int main() {
    init(); work();
    return 0;
}
 
      我已经不想再说些什么了,都是泪啊。卡了n久的常数,最后还是在正确的时间、正确的地……好吧,其实是在RP的强大作用下收获了两个AC。本来考虑是中间这四个点特判一下,后来想想如果被别人给hack了还不是一样?所以最后就是这个样了,我提供的程序保证输出的正确性但不保证速度,如果想要追求速度可以去看std,虽然不明白为什么同样的方法std就是要比我快,估计这就是大神和蒟蒻的差别了……
      UPD1 : 据说替罪羊树常数要比Treap小?如果哪天我闲了没事,试试把Treap改成替罪羊树,估计卡不掉了吧……
      UPD2 : 今天早上抱着复习替罪羊树的态度把Treap改成了替罪羊树,可能是因为没打结构体,或者是我的替罪羊树打萎了,最后速度反而更慢了……囧……
//Treap+动态点分治+替罪羊式重构
#include <cstdio>
#include <algorithm>
#include <cstdlib>
#include <ctime>
using namespace std;
typedef long long ll;
typedef double D;
const int N=200010;
const int M=14001000;
const int K=16;
const int BUF=20000000;
int n,rcnt,r[N];
int dep[N],dist[N],anc[N][17];
int pre[N],sz[N];
ll lastans;
char Buf[BUF],*buf=Buf;
inline void read(int&a){for(a=0;*buf<48;buf++);while(*buf>47)a=a*10+*buf++-48;}
struct Treap* null;
struct Treap* root[N];
struct Treap* rec[M];
struct Treap {
    Treap *fa,*son[2];
    int sz,key,data,pos;
    inline void updata() {
        if (this==null) return;
        this->sz=son[0]->sz+son[1]->sz+1;
    }
    inline void rotate() {
        Treap *x=this,*y=x->fa;
        int w=(y->son[0]==x);
        if (y->fa!=null) {
            Treap *z=y->fa;
            if (z->son[0]==y) z->son[0]=x;
            else z->son[1]=x;
        } else root[x->pos]=x;
        x->fa=y->fa; y->fa=x;
        if (x->son[w]!=null) x->son[w]->fa=y;
        y->son[w^1]=x->son[w];
        x->son[w]=y; y->updata(); x->updata();
    }
    inline void insert(Treap *t) {
        if (this==null) {
            root[t->pos]=t;
            return;
        } Treap *x=this;
        if (t->data<x->data) {
            if (x->son[0]!=null) x->son[0]->insert(t);
            else x->son[0]=t,t->fa=x;
            if (x->son[0]->key<x->key) x->son[0]->rotate();
        } else {
            if (x->son[1]!=null) x->son[1]->insert(t);
            else x->son[1]=t,t->fa=x;
            if (x->son[1]->key<x->key) x->son[1]->rotate();
        } x->updata();
    }
    inline int ask(int x) {
        if (this==null) return 0;
        if (x<this->data) return this->son[0]->ask(x);
        else return this->son[0]->sz+1+this->son[1]->ask(x);
    }
    inline void recycle() {
        if (this==null) return;
        if (son[0]!=null) son[0]->recycle();
        if (son[1]!=null) son[1]->recycle();
        rec[++rcnt]=this;
    }
};
Treap pool[M];
Treap *len;
inline int getLCA(int x,int y) {
    if (dep[x]<dep[y]) swap(x,y);
    if (!anc[y][0]) return y;
    if (dep[x]!=dep[y]) for (int i=K;~i;i--) 
        while (dep[anc[x][i]]>=dep[y]) x=anc[x][i];
    if (x==y) return x;
    for (int i=K;~i;i--) while (anc[y][i]!=anc[x][i]) y=anc[y][i],x=anc[x][i];
    return anc[x][0];
}
inline Treap* newnode(int x) {
    Treap *t=(rcnt)?rec[rcnt--]:len++;
    t->son[0]=t->son[1]=t->fa=null;
    t->pos=0; t->key=rand(); t->data=x;
    t->sz=1;
    return t;
}
int cur,SZ[N],f[N],num;
int g[N],to[N],nxt[N],tot;
int vis[N];
inline void addedge(int x,int y) {
    to[++tot]=y; nxt[tot]=g[x]; g[x]=tot;
    to[++tot]=x; nxt[tot]=g[y]; g[y]=tot;
}
inline void find(int x,int fat,int K) {
    SZ[x]=1; f[x]=0;
    for (int k=g[x];k;k=nxt[k]) if (to[k]!=fat&&vis[to[k]]!=K) {
        find(to[k],x,K);
        SZ[x]+=SZ[to[k]];
        if (SZ[to[k]]>f[x]) f[x]=SZ[to[k]];
    } if (num-SZ[x]>f[x]) f[x]=num-SZ[x];
    if (f[x]<f[cur]) cur=x;
}
inline void dfs(int x,int fat,int K) {
    for (int k=g[x];k;k=nxt[k]) 
        if (to[k]!=fat&&vis[to[k]]!=K) dfs(to[k],x,K);
    root[x]->recycle(); root[x]=null;
    root[x+n]->recycle(); root[x+n]=null;
}
inline void dfs1(int x,int fat,int K,int a) {
    int k,lca=getLCA(x,a);
    Treap *t=newnode(dist[x]+dist[a]-(dist[lca]<<1)-r[x]);
    t->pos=a; root[a]->insert(t);
    for (k=g[x];k;k=nxt[k]) 
        if (to[k]!=fat&&vis[to[k]]!=K) dfs1(to[k],x,K,a);
}
inline void dfs2(int x,int fat,int K,int a,int b) {
    int k,lca=getLCA(x,a);
    Treap *t=newnode(dist[x]+dist[a]-(dist[lca]<<1)-r[x]);
    t->pos=b; root[b]->insert(t);
    for (k=g[x];k;k=nxt[k]) 
        if (to[k]!=fat&&vis[to[k]]!=K) dfs2(to[k],x,K,a,b);
}
inline void solve(int x,int K) {
    vis[x]=K; dfs1(x,0,K,x);
    dfs2(x,0,K,pre[x],x+n);
    for (int k=g[x];k;k=nxt[k]) if (vis[to[k]]!=K) {
        num=SZ[to[k]];
        find(to[k],cur=0,K);
        pre[cur]=x;
        sz[cur]=num;
        solve(cur,K);
    }
}
inline bool rebuild(int x,int K) {
    if (pre[x]) {
        if (rebuild(pre[x],K)) return true;
        if (sz[x]>sz[pre[x]]*0.81) {
            dfs(pre[x],0,K);
            num=sz[pre[x]];
            find(pre[x],cur=0,K);
            pre[cur]=pre[pre[x]];
            sz[cur]=num;
            solve(cur,K);
            return true;
        } vis[pre[x]]=K;
    } return false;
}
int main() {
    fread(Buf,1,BUF,stdin);
    int i,j,x,y,dis,lca; f[0]=1000000;
    srand((unsigned)time(NULL));
    Treap *t;
    read(x); read(n);
    len=pool; null=len++;
    null->fa=null->son[0]=null->son[1]=null;
    null->pos=null->sz=0;
    null->key=null->data=0;
    for (i=1;i<=n<<1;i++) root[i]=null;
    for (i=1;i<=n;i++) {
        read(pre[i]); read(x); read(r[i]);
        pre[i]^=(lastans%1000000000);
        if (pre[i]) addedge(pre[i],i);
        dist[i]=dist[pre[i]]+x;
        anc[i][0]=pre[i];
        dep[i]=dep[pre[i]]+1;
        for (j=1;j<=K;j++) anc[i][j]=anc[anc[i][j-1]][j-1];
        for (dis=x,x=pre[i];x;x=pre[x]) {
            lastans+=root[x]->ask(r[i]-dis);
            if (pre[x]) {
                lca=getLCA(i,pre[x]);
                dis=dist[i]+dist[pre[x]]-(dist[lca]<<1);
                lastans-=root[x+n]->ask(r[i]-dis);
            }
        }
        for (dis=0,x=i;x;x=pre[x]) {
            t=newnode(dis-r[i]); t->pos=x;
            root[x]->insert(t); sz[x]++;
            if (pre[x]) {
                lca=getLCA(i,pre[x]);
                dis=dist[i]+dist[pre[x]]-(dist[lca]<<1);
                t=newnode(dis-r[i]);
                t->pos=x+n;
                root[x+n]->insert(t);
            }
        } rebuild(pre[i],i);
        printf("%lld\n",lastans);
    }
    return 0;
}
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string>
#include <vector>
#include <climits>
using namespace std;
typedef long long int64;
const int MAX_N = int(1e5) + 10;
const int MOD = int(1e9);
int n, r[MAX_N];
struct Edge {
	int t, c;
	Edge(int t, int c) :
			t(t), c(c) {
	}
};
vector<Edge> E[MAX_N];

//r_i+r_j-dist_i-dist_j>=0
//r_i-dist_i>=-r_j+dist_j
//val[i]=-r[i]+dist_j
//val[i]+val[j]<=0
//val[j]<=-val[i]

struct Node {
	Node*ch[2];
	int key, value, size;

	Node* set(int _value);

	Node() {
		size = 0;
		key = INT_MAX;
	}

	void update() {
		size = ch[0]->size + ch[1]->size + 1;
	}
} Tnull, *null = &Tnull;

Node* Node::set(int _value) {
	value = _value;
	size = 1;
	key = rand();
	ch[0] = ch[1] = null;
	return this;
}

const int BUFFER_SIZE = 10000;
Node*pool = 0, *cur = 0;
vector<Node*> stack;

Node*get() {
	if (!stack.empty()) {
		Node*u = stack.back();
		stack.pop_back();
		return u;
	}
	if (cur == 0 || cur == pool + BUFFER_SIZE)
		pool = new Node[BUFFER_SIZE], cur = pool;
	return cur++;
}

void recycle(Node*u) {
	stack.push_back(u);
}

struct Treap {
	Node*root;
	bool first;

	Treap() {
		root = null, first = true;
		//cout<<root<<endl;
	}

	void rotate(Node*&t, bool d) {
		Node*p = t->ch[d];
		t->ch[d] = p->ch[!d];
		p->ch[!d] = t;
		t->update();
		p->update();
		if (t == root)
			root = p;
		t = p;
	}

	void doInsert(Node*&t, int x) {
		if (t == null) {
			t = get()->set(x);
//			t = new Node(x);
			return;
		}
		bool dir = x > t->value;
		doInsert(t->ch[dir], x);
		if (t->ch[dir]->key < t->key)
			rotate(t, dir);
		else
			t->update();
	}

	int doCountSmall(Node*t, int x) {
		if (t == null)
			return 0;
		if (t->value >= x) {
			return doCountSmall(t->ch[0], x);
		}
		return doCountSmall(t->ch[1], x) + 1 + t->ch[0]->size;
	}

	void recycle(Node*u) {
		if (u == null)
			return;
		for (int i = 0; i < 2; ++i) {
			recycle(u->ch[i]);
		}
		::recycle(u);
	}

	vector<int> v;

	void recycle() {
		recycle(root);
		root = null;
		first = true;
		v.clear();
	}

	void insert(int x) {
		if (first) {
			v.push_back(x);
			return;
		}
		doInsert(root, x);
	}

	int countSmall(int x) {
		if (first) {
			first = false;
			sort(v.begin(), v.end());
		}
		return lower_bound(v.begin(), v.end(), x) - v.begin()
				+ doCountSmall(root, x);
	}
};

const double ALPHA = 0.9;

struct Split;

//val=-r_j+dist_j

struct SplitPtrsAtVertex;

struct SplitPtr {
	Split*sp;
	SplitPtrsAtVertex*v;
	int at, val;
};

Split*firstBad;

struct Split {
	//Branch
	Treap all;
	vector<Treap> treaps;
	vector<int> size;

	vector<SplitPtr*> ptrs;

	int total, maxSize;

	void reset() {
		all.recycle();
		for (int i = 0; i < treaps.size(); ++i)
			treaps[i].recycle();
		treaps.clear();
		size.clear();
		ptrs.clear();

		total = maxSize = 0;
	}

	bool bad() {
		return maxSize > 0.9 * total + 1;
	}

	void add(SplitPtr*p) {
		ptrs.push_back(p);
		all.insert(p->val);
		treaps[p->at].insert(p->val);

		size[p->at]++;
		total++;
		maxSize = max(maxSize, size[p->at]);

		if (bad() && firstBad == 0)
			firstBad = this;
	}

	int evalAnswer(SplitPtr*p) {
		return all.countSmall(-p->val + 1)
				- treaps[p->at].countSmall(-p->val + 1);
	}
};

Split spAt[MAX_N];

struct SplitPtrsAtVertex {
	int id;
//	vector<SplitPtr*> ptrs;

	int cnt;
	SplitPtr ptrs[80];

	SplitPtrsAtVertex() {
		cnt = id = 0;
	}

	SplitPtr* newSplitPtr(Split*sp, int at, int val) {
		SplitPtr*ptr = ptrs + (cnt++);
		ptr->v = this;
		ptr->sp = sp, ptr->at = at, ptr->val = val;
		return ptr;

//		ptrs.push_back(ptr);
	}

	void remove(SplitPtr*p) {
		for (;;) {
//			SplitPtr*t = ptrs.back();
			SplitPtr*t = ptrs + (cnt - 1);
//			ptrs.pop_back();
			cnt--;
			if (t == p)
				break;
		}
	}
};

SplitPtrsAtVertex at[MAX_N];
bool del[MAX_N];

int seq[MAX_N], pt, opt[MAX_N], size[MAX_N];

void dfs(int u, int par) {
	size[u] = 1, seq[pt++] = u;
	opt[u] = 0;
	for (vector<Edge>::iterator e = E[u].begin(); e != E[u].end(); ++e)
		if (e->t != par && !del[e->t]) {
			dfs(e->t, u), size[u] += size[e->t];
			opt[u] = max(opt[u], size[e->t]);
		}
}

void dfs2(int u, int par, int val, Split*sp, int at) {

	SplitPtr*ptr = ::at[u].newSplitPtr(sp, at, val - r[u]);
//	sp->maps[at].ensure(val);
//	sp->all.ensure(val);
	sp->add(ptr);
//	::at[u].addSplitPtr(ptr);

	for (vector<Edge>::iterator e = E[u].begin(); e != E[u].end(); ++e)
		if (e->t != par && !del[e->t]) {
			dfs2(e->t, u, val + e->c, sp, at);
		}
}

void build(int rt) {
	pt = 0, dfs(rt, -1);
	int tot = size[rt];
	int minOpt = tot + 1, by = -1;
	for (int i = 0; i < tot; ++i) {
		int u = seq[i];
		opt[u] = max(opt[u], tot - size[u]);
		if (opt[u] < minOpt)
			minOpt = opt[u], by = u;
	}

	rt = by;
	int cnt = 0;
	del[rt] = true;

	Split*sp = spAt + rt;

	for (vector<Edge>::iterator e = E[rt].begin(); e != E[rt].end(); ++e)
		if (!del[e->t]) {
			sp->treaps.push_back(Treap());
			sp->size.push_back(0);
			dfs2(e->t, rt, e->c, sp, cnt), cnt++;
		}

//	sp->all.ensure(value[rt]);
	sp->treaps.push_back(Treap());
	sp->size.push_back(0);
	SplitPtr*ptr = at[rt].newSplitPtr(sp, cnt, 0 - r[rt]);
	sp->add(ptr);
//	at[rt].addSplitPtr(ptr);
	cnt++;

	for (vector<Edge>::iterator e = E[rt].begin(); e != E[rt].end(); ++e)
		if (!del[e->t]) {
			build(e->t);
		}
}

void rebuild(Split*sp) { //rebuild this
	int u;
	vector<int> which;
	for (int i = 0; i < sp->ptrs.size(); ++i) {
		SplitPtr*p = sp->ptrs[i];
		del[p->v->id] = false;
		u = p->v->id;
		p->v->remove(p);
		which.push_back(u);
	}

	for (int i = 0; i < which.size(); ++i)
		spAt[which[i]].reset();

	build(u);
}

int addEdge(int a, int b, int c) {
	if (a == -1) {
		build(b);
		return 0;
	}

	E[a].push_back(Edge(b, c));
	E[b].push_back(Edge(a, c));

	firstBad = 0;
//a<b,build at[b]
	at[b].id = b;
	int ret = 0;
	for (int i = 0; i < at[a].cnt; ++i) {
		SplitPtr*p = at[a].ptrs + i;
		int dist = p->val + r[a] + c;
		if (i + 1 < at[a].cnt) {
			SplitPtr*np = at[b].newSplitPtr(p->sp, p->at, -r[b] + dist);

			ret += np->sp->evalAnswer(np);
			np->sp->add(np);
//			at[b].addSplitPtr(np);
		} else {
			Split*sp = p->sp;
			sp->treaps.push_back(Treap());
			sp->size.push_back(0);
			SplitPtr*np = at[b].newSplitPtr(sp, sp->treaps.size() - 1,
					-r[b] + dist);
			ret += np->sp->evalAnswer(np);
			np->sp->add(np);
//			at[b].newaddSplitPtr(np);
		}
	}

	spAt[b].reset();
	build(b);

	if (firstBad != 0) {
		rebuild(firstBad);
	}

	return ret;
}

int main() {
	int nId;
	cin >> nId;
	cin >> n;
	int64 ans = 0;
//	fill(del, del + n, true);
	for (int i = 0; i < n; ++i) {
		int a, c;
		scanf("%d%d%d", &a, &c, r + i);
		a ^= (ans % MOD);
		--a;
		ans += addEdge(a, i, c);
		printf("%lld\n", ans);
	}

//	int maxLong = 0;
//	for (int i = 0; i < n; ++i) {
//		maxLong = max(maxLong, (int) at[i].ptrs.size());
//	}
//
//	cerr << maxLong << endl;
}
 
 
 
 
 
 
 
      大致就先坑到这里了,后面这些只有题目链接没有代码的都是我还没有坑而且估计不是一天两天就能坑完的,所以先扔在这儿,如果什么时候我能想起来这个坑的话,我一定会填完的……(为什么感觉这话各种没有志气)
      另:为什么感觉与人名有关的题目总是各种坑呢……

 

Emma 说:
2023年1月18日 19:06

In the lifetime series Code Farming, a few questions are asked in order to get an understanding of what the code farm is. The first question is, "What is a code farm?" A code farm is a place where code is grown. The natural CBD oil second question is, "How is code grown?" Code is grown by farmers who work on the land, using special machines to plant, grow, and harvest the code. The third question is, "What do code farmers do?" Code farmers work on the land, using special machines to plant, grow, and harvest the code.


登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter