1. 程式人生 > >[湖南集訓]談笑風生

[湖南集訓]談笑風生

[湖南集訓]談笑風生

LG傳送門

這題有很多方法做,一堆大佬用線段樹合併、主席樹來做,但是我太弱了,只會長鏈剖分。

長鏈剖分的解法,思維簡單,碼量極低,是你的不二之選!

還是老規矩,先上\(n^2\)DP。

題意就不說了,但是先注意到,如果\(b\)\(a\)的上方,\(c\)直接取\(a\)子樹中除了\(a\)的所有點就好了,DP的目的只是統計\(b\)\(a\)的下方的情況。

首先設\(f[i][j]\)表示如果把\(a\)取在\(i\)點,\(b\)取在以\(i\)為根的子樹中距離\(a\)\(j\)的點上的方案數。特別地,\(f[i][0]\)表示把\(b\)取在\(a\)

點上的方案數(其實就是子樹內除了\(a\)的所有點),然而實際上題目要求\(a\)\(b\)不是同一個點,記答案的時候需要減去它的貢獻,這樣定義只是為了方便轉移。

可以寫出轉移方程:\(f[i][j+1]=\sum f[t][i]\),其中\(t\)\(i\)的子節點。

觀察一下題目要求的東西,發現需要對\(f[i][j]\)求個字首和(意思是對於同一個\(i\),求\(j\)變化時的字首和),然而字首和不方便,那就求字尾和。

所以我們的\(f[i][j]\)的意義需要在原來的基礎上做一些調整,變成原來意義上的字尾和。方程沒有變:\(f[i][j+1]=\sum f[t][i]\),只是加上一句\(f[i][0]+=f[t][0]\)

就好了。

DP完一個點之後就統計答案,很簡單就不贅述了。

但是上面這個DP是\(O(n^2)\)的,由於下標是深度,套個長鏈剖分的板子就好了。不會長鏈剖分的同學可以看看我的長鏈剖分總結

#include<cstdio>
#include<cctype>
#include<algorithm>
#include<vector>
#define R register
#define I inline
using namespace std;
const int S=300003,N=600003;
char buf[S],*p1,*p2;
I char gc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,S,stdin),p1==p2)?EOF:*p1++;}
I int rd(){
    R int f=0; R char c=gc();
    while(c<48||c>57) c=gc();
    while(c>47&&c<58) f=f*10+(c^48),c=gc();
    return f;
}
int h[S],s[N],g[N],d[S],w[S],t[S],p[S],q[S],c; long long *f[S],u[S],o[S],*e=u+1;
vector<pair<int,int> > v[S];
I int min(int x,int y){return x<y?x:y;}
I void add(int x,int y){s[++c]=h[x],g[c]=y,h[x]=c;}
I void ini(int x){f[x]=e,e+=t[x]-d[x]+1;}
void dfs1(int x,int f){t[x]=d[x]=d[f]+1,p[x]=f,w[x]=1;
    for(R int i=h[x],y;i;i=s[i])
        if((y=g[i])^f){dfs1(y,x),w[x]+=w[y];
            if(t[y]>t[x]) t[x]=t[y],q[x]=y;
        }
}
void dfs2(int x){f[x][0]=w[x]-1;
    if(q[x]) f[q[x]]=f[x]+1,dfs2(q[x]),f[x][0]+=f[q[x]][0];
    R int i,j,k,y,m;
    for(i=h[x];i;i=s[i])
        if((y=g[i])^p[x]&&y^q[x])
            for(j=0,ini(y),dfs2(y),f[x][0]+=f[y][0],m=t[y]-d[y];j<=m;++j)
                f[x][j+1]+=f[y][j];
    for(i=0,m=v[x].size()-1;i<=m;++i){
        k=v[x][i].first,j=v[x][i].second,o[j]+=1ll*(w[x]-1)*min(d[x]-1,k);
        if(k>=t[x]-d[x]) o[j]+=f[x][0]-w[x]+1;
        else o[j]+=f[x][0]-w[x]+1-f[x][k+1];
    }
}
int main(){
    R int n=rd(),m=rd(),i,x,y;
    for(i=1;i<n;++i) x=rd(),y=rd(),add(x,y),add(y,x);
    for(dfs1(1,0),i=1;i<=m;++i) x=rd(),y=rd(),v[x].push_back(make_pair(y,i));
    for(ini(1),dfs2(1),i=1;i<=m;++i) printf("%lld\n",o[i]);
    return 0;
}