• 小奇的仓库(树形DP)


    「题目背景」

    小奇采的矿实在太多了,它准备在喵星系建个矿石仓库。令它无语的是,喵星系的货运飞船引擎还停留在上元时代!

    「问题描述」

    喵星系有n个星球,星球以及星球间的航线形成一棵树。

    从星球a到星球b要花费[dis(a,b) Xor M]秒。(dis(a,b)表示ab间的航线长度,Xor为位运算中的异或)

    为了给仓库选址,小奇想知道,星球i(1<=i<=n)到其它所有星球花费的时间之和。

    「输入格式」

    第一行包含两个正整数n,M。
    接下来n-1行,每行3个正整数a,b,c,表示a,b之间的航线长度为c。

    「输出格式」

    n行,每行一个整数,表示星球i到其它所有星球花费的时间之和。

    「样例输入」

    4 0

    1 2 1

    1 3 2

    1 4 3

    「样例输出」

    6

    8

    10

    12

    「数据范围」

    序号   N    M

     1    6    0

     2   100   5

     3  2000   9

     4  50000  0

     5  50000  0

     6  50000  1

     7  50000  6

     8  100000 10

     9  100000 13

     10 100000 15

    保证答案不超过2*10^9

    下面一段话是出题人神秘而不失优雅的题解

    算法1:

    不会写函数的小伙伴们,我们只需要写个floyd,就有10分啦!

    算法2:

    在算法1的基础上,我们对每条边处理一下xor,就有20分啦!

    算法3:

    简单的树形DP,或者你会nlogn的dij,处理完每个点到其它点的最短路后再加上xor,那么这样就有30分啦!

    算法4:

    第4、5个点无需xor,那么我们树形DP扫一个节点与其它所有节点的路径长度之和,可以合并信息,最终均摊O(1),50分到手。

    算法5:

    第6个点xor 1,那么我们树形DP到一个点时记录有多少个0,多少个1,然后每当一条路径到2,那部分就再记录一个值,60分到手。

    算法6:

    如果你第6个点都过了,却没有满分,笨死啦!

    一样的嘛,就是原来的“0”、“1”、大于等于2变成了0~16么~~

     


     

    下面是自己的话:

     既然是棵树,又要快速地求每个点的值,那一定是树形DP加上换根的操作啦~

    但是异或m要怎么处理呢?可以观察数据规模,发现m最大最大也就15,换成二进制数也就是 1111,所以发现异或m最多只会对数字的后面4位造成影响(异或0甚至无法造成什么影响)

    于是愉快地写出DP数组 f[i]sz[i][0~15]

     f表示此时以i为根的子树到i节点的距离之和(减去后缀后的和)

      sz表示此时距离以j为后缀的共有几个

    每一次向根节点方向转移时会加上一条边的长度,此时不同后缀距离的后缀会发生相应改变,然后更新父亲相应后缀的sz值。

    然后f里统计的距离总和是抹掉所有后缀后的总和,即不考虑后缀的贡献。如有一个距离是 10111(2),抹去长度为2的后缀后就只剩下10100,然后将这个结果加到f数组里,到最后根节点统计最终答案时再考虑每个后缀的贡献,此时的sz数组就派上用场了(具体看代码)

    还有一点,就是最后要把答案减去m,因为统计后缀贡献时,多加了自己到自己的距离(本来为0,xor m 后变成了m)。

    代码如下

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstdlib>
      4 #include<cstring>
      5 #include<algorithm>
      6 
      7 #define For(i,a,b) for(register int i=a;i<=b;++i)
      8 #define Re register
      9 #define Pn putchar('
    ')
     10 #define inf 0x7f7f7f
     11 #define llg long long
     12 using namespace std;
     13 const int N=1e5+10;
     14 int sz[N][17];
     15 int head[N],nxt[N*2],v[N*2],cnt=1;
     16 llg w[N*2],z,fn[N],f[N];
     17 int n,m,x,y,ct,tot;
     18 
     19 inline void read(int &v){
     20     v=0;
     21     char c=getchar();
     22     while(c<'0'||c>'9')c=getchar();
     23     while(c>='0'&&c<='9')v=v*10+c-'0',c=getchar();
     24 }
     25 inline void read(llg &v){
     26     v=0;
     27     char c=getchar();
     28     while(c<'0'||c>'9')c=getchar();
     29     while(c>='0'&&c<='9')v=v*10+c-'0',c=getchar();
     30 }
     31 void write(llg x){
     32     if(x>9)write(x/10);
     33     int xx=x%10;
     34     putchar(xx+'0');
     35 }
     36 
     37 void add(int ux,int vx,llg wx){
     38     cnt++;
     39     nxt[cnt]=head[ux]; head[ux]=cnt; v[cnt]=vx; w[cnt]=wx;
     40     cnt++;
     41     nxt[cnt]=head[vx]; head[vx]=cnt; v[cnt]=ux; w[cnt]=wx;
     42 }
     43 
     44 void DFS1(int x,int fa){
     45     sz[x][0]=1;  
     46     for(Re int i=head[x];i;i=nxt[i]){
     47         int vv=v[i];
     48         if(vv==fa)continue;
     49         DFS1(vv,x);
     50         f[x]+=f[vv];
     51         For(j,0,tot){
     52             int Nsm=j+w[i];
     53             int Nst=Nsm & ct;
     54             sz[x][Nst]+=sz[vv][j];
     55             f[x]+=sz[vv][j]*(Nsm-Nst);
     56         }
     57     }
     58 }
     59 int Bsz[N][20];
     60 void DFS2(int x,int fa){   //换根 
     61     fn[x]=f[x];
     62     For(st,0,tot){
     63         fn[x]+=(st^m)*sz[x][st];
     64     }
     65     For(st,0,tot)Bsz[x][st]=sz[x][st];
     66     llg Bf=f[x];
     67     
     68     for(Re int i=head[x];i;i=nxt[i]){
     69         int vv=v[i];
     70         if(vv==fa)continue;
     71         
     72         int Nsm,Nst;
     73          
     74         For(st,0,tot){
     75             Nsm =st+w[i];
     76             Nst=Nsm&ct;
     77             sz[x][Nst]-=sz[vv][st];
     78             f[x]-=sz[vv][st]*(Nsm-Nst);
     79         }
     80     
     81         f[vv]=f[x];
     82         For(st,0,tot){
     83             Nsm=st+w[i];
     84             Nst=Nsm&ct;
     85             sz[vv][Nst]+=sz[x][st];
     86             f[vv]+=sz[x][st]*(Nsm-Nst);
     87         }
     88 
     89         DFS2(vv,x);
     90         
     91         f[x]=Bf;
     92         For(st,0,tot)sz[x][st]=Bsz[x][st];
     93     }    
     94 }
     95 
     96 int main(){
     97 //    freopen("warehouse.in","r",stdin);
     98 //    freopen("warehouse.out","w",stdout);
     99     read(n); read(m);
    100     
    101     if(m==0)ct=0,tot=0;
    102     if(m==1)ct=1,tot=1;
    103     if(m==5)ct=7,tot=7;
    104     if(m==6)ct=7,tot=7;
    105     if(m>=9)ct=15,tot=15;  //简单粗暴的预处理 
    106     
    107     For(i,1,n-1){
    108         read(x); read(y); read(z);
    109         add(x,y,z);
    110     }
    111     DFS1(1,0);
    112     DFS2(1,0);
    113     For(i,1,n){
    114          write(fn[i]-m); Pn;
    115     }
    116     return 0;
    117 }

     

     

     

  • 相关阅读:
    [IOI1994][USACO1.5]数字三角形 Number Triangles
    和为给定数
    小凯的疑惑
    棋盘
    【2020NOI.AC省选模拟#2】C. 送分题
    【NOI OL #2】涂色游戏
    【NOI OL #3】小结
    【NOI OL #1】最小环
    【NOI OL #1】冒泡排序
    【NOI OL #1】序列
  • 原文地址:https://www.cnblogs.com/HLAUV/p/9890073.html
Copyright © 2020-2023  润新知