首先先说一下最后一个测试点很多人RE的问题,我来了一张图:
大概就是图里的那样…
下面是我的思路:
可能稍微复杂一点…
首先,题意我就不说了,关键在于每一层的边长度不同:
大佬们已经推出来这么个东西:
1
| f[20]={0,1,2,5,11,23,47,95,191,383,767};
|
其中f[i]就是高度为i的那一层到它上一层的边的长度(这里的高度指的是由下往上数的高度,为了方便我把最下边设为了1)
举个例子(样例):
也就是说f[i]存的就是第i层到第i-1层的边的长度(几个’/‘或’\’)
我是先把最下边一层先初始化弄进去,因为我不知道n,所以我从我开的画布数组最下边一行开始,从下往上:
1 2 3 4 5 6 7
| cin>>n>>k; num=1<<(n-1); for(long long i=1,j=1;i<=num/2;++i,j+=6) { paint[19000][j]='o'; paint[19000][j+4]='o'; }
|
两个一组,很容易得出最下面一行共需要(2^(n-1))/2次循环,每次直接两个都放进去’o’,然后很容易的j每次加6(横坐标)
然后从倒数第二行开始模拟往画布里填’o’或’/‘或’\’
我们可以这样:计算出当前行的最左/最右结点在画布里的坐标为循环边界,从左边(当前行的所有结点视为向上一行的结点的孩子),即左孩子开始,向右上方朝父节点画’/’.
但是要画几次呢?这时我们的f[]数组就派上用场了…从第i层向上画’/'当然画f[i]次了,然后画完边后再向右上一格把父节点也就是’o’画上,然后从父结点再往右下画回到右孩子,然后这一个子树画完再画旁边的树,画个流程图吧:
就是这样,先上去,再下来,然后虚线跳到下一个子树,注意这时跳跃的长度每层是不一样的,我们用s[]来存,很容易得出(跟f[]很类似):
1
| s[20]={0,2,6,12,24,48,96,192,384,768,1536};
|
每次横坐标加就行了
这样,我们最后就有了一个完全二叉树,然后就是去节点了.
画布里存得是点或边在这张"画"里得坐标,而题目输入进来得是结点在树中得坐标,这时我们就开一个结构体数组存树,数组的每个元素为结点,每个元素(都是一个结构体变量)里的结构体成员x和y存的是通过计算求得的在画布里的坐标,然后找到要删除的点,把它和它的子树所在的一个正方形区都归为’ '(空格),如图:
然后,愉快的输出就行了,其他的细节在代码中:
AC代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
| #include<bits/stdc++.h> using namespace std; long long n,k,num,x,y,line=19000; long long l,r,f[20]={0,1,2,5,11,23,47,95,191,383,767}; long long s[20]={0,2,6,12,24,48,96,192,384,768,1536}; char paint[20001][5000]; struct TREE { long long x,y; }tree[1040]; void draw(long long i) { x=line,y=l; l=y+f[i]+1; for(long long j=1;j<=num/2;++j) { for(long long k=1;k<=f[i];++k) paint[--x][++y]='/'; paint[--x][++y]='o'; for(long long k=1;k<=f[i];++k) paint[++x][++y]='\\'; ++x; y++; y+=s[i]; } y-=s[i]; r=y-f[i]-1; line=x-f[i]-1; num/=2; } void remove_down_all(long long up,long long r_l,long long r_r) { for(long long i=up;i<=19000;++i) for(long long j=r_l;j<=r_r;++j) paint[i][j]=' '; } void remove_up_edge(long long x,long long y) { long long ex=x-1,ey=y-1; if(paint[ex][ey]!=' ') while(paint[ex][ey]!='o') paint[ex--][ey--]=' '; ex=x-1,ey=y+1; if(paint[ex][ey]!=' ') while(paint[ex][ey]!='o') paint[ex--][ey++]=' '; } int main() { cin>>n>>k; if(n==0) { cout<<endl; return 0; } memset(paint,' ',sizeof(paint)); num=1<<(n-1); long long num2=num; long long len=0; long long to=(num2/2)*6-1; l=1;r=(num/2)*6-1; for(long long i=1,j=1;i<=num/2;++i,j+=6) { paint[19000][j]='o'; paint[19000][j+4]='o'; } for(long long i=1;i<n;++i) draw(i);
for(long long i=line;i<=19000;++i) for(long long j=1;j<=to;++j) { if(paint[i][j]=='o') { tree[++len].x=i; tree[len].y=j; } } long long t,y1,y2; for(long long i=1;i<=k;++i) { scanf("%d%d",&x,&y); t=1<<(x-1); t=t+y-1; if(t>len)continue; x=tree[t].x; y=tree[t].y; y1=y-(19000-x); y2=y+(19000-x);
remove_down_all(x,y1,y2); remove_up_edge(x,y); } for(long long i=line;i<=19000;++i) { for(long long j=1;j<=to;++j) cout<<paint[i][j]; cout<<endl; } }
|
管理员求过…真的是自己的做法