【BZOJ3522&BZOJ4543】Hotel加强版(长链剖分,树形DP)

题意:求一颗树上三点距离两两相等的三元组对数

n<=1e5

思路:From https://blog.bill.moe/bzoj4543-hotel/

f[i][j]表示以i为根的子树中距离i为j的点的个数

g[i][j]表示以i为根的子树中两点距离他们的lca为d,lca距离i为d-j的两点对数

g[i][j]找到一个子树外的f[i][j]就对答案有贡献

朴素的方程为:设v为u的一个儿子

ans+=f[u][j]*g[v][j+1]+g[u][j]*f[y][j-1]

g[u][j+1]+=f[u][j+1]*f[v][j]

g[u][j-1]+=g[v][j]

f[u][j+1]+=f[v][j]

显然f[i][j]只和深度有关,且f[u]的[1,len[u]]这一段是所有f[v]的[0,len[u]-1]右移一位之和

为了防止同一个子树中的信息算多了,先算ans部分再执行后面三步更新

指针的写法我完全是抄的

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 typedef long long ll;
  4 typedef unsigned int uint;
  5 typedef unsigned long long ull;
  6 typedef pair<int,int> PII;
  7 typedef pair<ll,ll> Pll;
  8 typedef vector<int> VI;
  9 typedef vector<PII> VII;
 10 typedef pair<ll,int>P;
 11 #define N  100010
 12 #define M  200010
 13 #define fi first
 14 #define se second
 15 #define MP make_pair
 16 #define pi acos(-1)
 17 #define mem(a,b) memset(a,b,sizeof(a))
 18 #define rep(i,a,b) for(int i=(int)a;i<=(int)b;i++)
 19 #define per(i,a,b) for(int i=(int)a;i>=(int)b;i--)
 20 #define lowbit(x) x&(-x)
 21 #define Rand (rand()*(1<<16)+rand())
 22 #define id(x) ((x)<=B?(x):m-n/(x)+1)
 23 #define ls p<<1
 24 #define rs p<<1|1
 25 
 26 const ll MOD=1e9+7,inv2=(MOD+1)/2;
 27       double eps=1e-6;
 28       int INF=1<<30;
 29       ll inf=5e13;
 30       int dx[4]={-1,1,0,0};
 31       int dy[4]={0,0,-1,1};
 32 
 33 int head[M],vet[M],nxt[M],tot;
 34 int len[N],son[N];
 35 ll tmp[N*5],*f[N],*g[N],*now=tmp,ans;
 36 
 37 int read()
 38 {
 39    int v=0,f=1;
 40    char c=getchar();
 41    while(c<48||57<c) {if(c=='-') f=-1; c=getchar();}
 42    while(48<=c&&c<=57) v=(v<<3)+v+v+c-48,c=getchar();
 43    return v*f;
 44 }
 45 
 46 void add(int a,int b)
 47 {
 48     nxt[++tot]=head[a];
 49     vet[tot]=b;
 50     head[a]=tot;
 51 }
 52 
 53 void dfs(int u,int fa,int d)
 54 {
 55     len[u]=0;
 56     int e=head[u];
 57     while(e)
 58     {
 59         int v=vet[e];
 60         if(v!=fa)
 61         {
 62             dfs(v,u,d+1);
 63             if(len[v]>len[son[u]])
 64             {
 65                 son[u]=v;
 66                 len[u]=len[v]+1;
 67             }
 68         }
 69         e=nxt[e];
 70     }
 71 }
 72 
 73 void solve(int u,int fa)
 74 {
 75     if(son[u])
 76     {
 77         f[son[u]]=f[u]+1;
 78         g[son[u]]=g[u]-1;
 79         solve(son[u],u);
 80     }
 81     f[u][0]=1;
 82     ans+=g[u][0];
 83     int e=head[u];
 84     while(e)
 85     {
 86         int v=vet[e];
 87         if(v!=fa&&v!=son[u])
 88         {
 89             f[v]=now;
 90             now+=(len[v]<<1)+2;
 91             g[v]=now;
 92             now+=(len[v]<<1)+2;
 93             solve(v,u);
 94             rep(j,0,len[v])
 95             {
 96                 if(j) ans+=f[u][j-1]*g[v][j];
 97                 ans+=g[u][j+1]*f[v][j];
 98             }
 99             rep(j,0,len[v])
100             {
101                 g[u][j+1]+=f[u][j+1]*f[v][j];
102                 if(j) g[u][j-1]+=g[v][j];
103                 f[u][j+1]+=f[v][j];
104             }
105         }
106         e=nxt[e];
107     }
108 }
109 int main()
110 {
111     int n=read();
112     tot=0;
113     rep(i,1,n-1)
114     {
115         int x=read(),y=read();
116         add(x,y);
117         add(y,x);
118     }
119     len[0]=-1;
120     dfs(1,0,1);
121     ans=0;
122     f[1]=now,now+=(len[1]<<1)+2,g[1]=now,now+=(len[1]<<1)+2;
123     solve(1,0);
124     printf("%lld\n",ans);
125     return 0;
126 }

 

posted on 2019-09-22 16:44  myx12345  阅读(207)  评论(0编辑  收藏  举报

导航