• 【墨西哥区域赛】Carpet


    原题:

    题意:

    给你一个树,有1e5个节点,让你把这个树放在一个长1e6宽20的网格图里,要求一个格子放一个节点,树边之间不能相交

    这是一道构造题

    因为树的形状可能性很多,很复杂,所以不能简单猜测,而必须要依据某种性质,来保证生成的解一定合法

    先尝试小规模,或特殊的问题也是一个重要的思想方法

    首先考虑一个节点A和它的所有儿子

    不难发现,这时可以把这个节点放在某层,然后把它的儿子放在下一层的一个区间内

    只要爸爸出现的顺序和儿子所在区间出现的顺序相同,就不会发生冲突

    因为在两层之间连边,斜率只会无限趋于0,所以不会出现于(xA, yA+1)和(xA, yA-1)冲突的情况,只需保证这两层之间的边不相交

    继而可以发现,只要满足这个条件,不管A和它的儿子们在什么位置,都不会和别人冲突

    为了压缩空间,所有的儿子可以连续放在一起,即使和爸爸相距太远也没有问题

    其次,题目数据中宽度为20

    根据经验,与众不同的数字往往有重要含义

    可以敏感地发现20刚好是log1e6

    联系到树链剖分

    因为重链剖分保证任意一个节点到根节点的路径最多只会经过logn条重链

    所以可以让一条重链躺在一层,而轻儿子都放到下一层,根节点放左上角

    这样对于任意一点,想要通过构造的网格图去往根节点,至多会往上爬logn层

    所以深度不会超过限制,而宽度显然充足

    所以问题就解决了

    轻儿子放在连续的区间,区间出现的顺序和爸爸出现的顺序相同,这能保证不发生冲突

    进行树链剖分,重链剖分的性质保证深度不会超过限制

    代码:

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<algorithm>
     4 #include<cstring>
     5 #include<cmath>
     6 using namespace std;
     7 int rd(){int z=0;  char ch=getchar();
     8     while(ch<'0'||ch>'9')  ch=getchar();
     9     while(ch>='0'&&ch<='9'){z=(z<<3)+(z<<1)+ch-'0';  ch=getchar();}
    10     return z;
    11 }
    12 struct edg{int y,nxt;}e[210000];  int lk[110000],ltp=0;
    13 void ist(int x,int y){
    14     e[++ltp]=(edg){y,lk[x]};  lk[x]=ltp;
    15     e[++ltp]=(edg){x,lk[y]};  lk[y]=ltp;
    16 }
    17 int n;
    18 int fth[110000],hvc[110000],sz[110000];
    19 int ax[110000],ay[110000];
    20 int hd[30];
    21 void dfs1(int x,int y){
    22     fth[x]=y;  sz[x]=1;
    23     int mx=0,mxid=0;
    24     for(int i=lk[x];i;i=e[i].nxt)if(e[i].y!=y){
    25         dfs1(e[i].y,x);
    26         sz[x]+=sz[e[i].y];
    27         if(sz[e[i].y]>mx)  mx=sz[e[i].y],mxid=e[i].y;
    28     }
    29     hvc[x]=mxid;
    30 }
    31 void dfs(int x,int y){
    32     ay[x]=y,ax[x]=++hd[y];
    33     for(int i=lk[x];i;i=e[i].nxt)if(e[i].y!=fth[x] && e[i].y!=hvc[x])
    34         dfs(e[i].y,y+1);
    35     if(hvc[x])  dfs(hvc[x],y);
    36 }
    37 int main(){
    38     //freopen("ddd.in","r",stdin);
    39     memset(lk,0,sizeof(lk));
    40     memset(hd,0,sizeof(hd));
    41     cin>>n;
    42     int l,r;
    43     for(int i=1;i<n;++i){
    44         l=rd(),r=rd();
    45         ist(l,r);
    46     }
    47     dfs1(1,0);
    48     dfs(1,1);
    49     for(int i=1;i<=n;++i)  printf("%d %d
    ",ax[i],ay[i]);
    50     return 0;
    51 }
    View Code
  • 相关阅读:
    Ahoi2013 作业
    bzoj 2502 清理雪道 (有源汇上下界最小流)
    zoj 3229 Shoot the Bullet(有源汇上下界最大流)
    TCP协议和socket API 学习笔记
    http、TCP/IP协议与socket之间的区别
    ios多线程和进程的区别(转载)
    iOS进程间通信之CFMessagePort
    功能强大的Xcode辅助工具Faux Pas:帮你找到各种隐形的bug
    [深入浅出Cocoa]iOS程序性能优化
    IOS之禁用UIWebView的默认交互行为
  • 原文地址:https://www.cnblogs.com/cdcq/p/11564565.html
Copyright © 2020-2023  润新知