EEE

路径

https://ac.nowcoder.com/acm/contest/10743/E

题目中问到关于所有路径的问题,这样我们很自然就能想到需要通过点分治来解决此类问题(我跟你讲淀粉质可好吃了),然后我们需要进一步解决的就是如何快速统计之后的答案,题目中出题人很良心的告诉了∑z的数据范围1≤∑z≤2×10^5所以我可以统计一个前缀和然后二分查找答案(zz的storm竟然写了一个treap,然后T了),这个二分可以通过STL的lower_bound实现,然后我们这样写就过了。所以这道题实质上是一道非常好的点分治的模板题。
经过出题人的提醒,我才意识到这个做法是错误的。对于一个菊花图来说,如果用一个桶来更新的话,我们的更新复杂度可能会被卡到S^2(S=路径的个数),这样对于这个题来说是不可以通过的,那么我们就需要来优化复杂度,通过观察我们统计答案的步骤我们可以,得到一个a[]数组,角标i就是表示路径长度为i的个数,这样我们就可以用每次getdis()更新的路径与他卷积之后就可以更新答案,最后统计答案的做法不变。经过我的不懈努力终于写了出来,提交之后会发现T掉了最后10%的数据,在看了题解区dalao的评论之后,我发现这个做法并不会是官方题解给出复杂度严格SlogS如果一直统计较大的路径这种做法也会劣化,我们采取的做法是由路径长度由小到大更新。
最后吐槽一句,这个题不卡N^2暴力不卡裸的点分治,而且正解NTT竟然会比N^2暴力还慢?

#include<cstdio>
#include<set>
#include<iostream>
#include<ctime>
#include<cmath>
#include<algorithm>
using namespace std;
#define maxn 1000010
#define maxs 1000010
#define INF 0x3f3f3f3f
const int mod = 1e9+7;
const double pie=acos(-1);

namespace IO {
    template <typename T>
    inline void w(T x) { if (x > 9) w(x / 10); putchar(x % 10 + 48); }
    template <typename T>
    inline void write(T x, char c) { if(x < 0) putchar('-'), x = -x; w(x); putchar(c); }
    template <typename T>
    inline void read(T &x) {
        x = 0; T f = 1; char c = getchar();
        for (; !isdigit(c); c = getchar()) if (c == '-') f = -1;
        for (; isdigit(c); c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48);
        x *= f;
    }
};

int e[maxn],ne[maxn],h[maxn],cst[maxn],bit,dis[maxn],idx=1,sz[maxn],maxx[maxn],sum,root,ans[maxs],rev[maxs],lena,lenb,a[maxs],b[maxs],tot,maxdep;
bool vis[maxn];

void add(int a,int b,int c){
    e[idx]=b;ne[idx]=h[a];cst[idx]=c;h[a]=idx++;
    e[idx]=a;ne[idx]=h[b];cst[idx]=c;h[b]=idx++;
}

struct cp{
    double real,imaginary;
    cp operator +(cp that){
        return (cp){real+that.real,imaginary+that.imaginary};
    }
    cp operator -(cp that){
        return (cp){real-that.real,imaginary-that.imaginary};
    }
    cp operator *(cp that){
        return (cp){real*that.real-imaginary*that.imaginary,imaginary*that.real+real*that.imaginary};
    }
}f[maxn],g[maxn];

void FFT(cp *F,int len,int flag){
    for(int i=1;i<len;i++){
        rev[i]=(rev[i>>1]>>1|(i&1)<<bit);
        if(i<rev[i])
            swap(F[i],F[rev[i]]);
    }
    for(int i=1;i<len;i<<=1){
        cp x,y,wn={cos(pie/i),flag*sin(pie/i)};
        for(int j=0,add=i<<1;j<len;j+=add){
            cp w=(cp){1,0};
            for(int k=0;k<i;k++,w=w*wn){
                x=F[j+k];y=w*F[i+j+k];
                F[j+k]=x+y;F[i+j+k]=x-y;  
            }
        }
    }
    return;
}

void work(int n,int m){
    int len=1;
    bit=0;
    while(len<=n+m){
        len<<=1;
        bit++;
    }bit--;
    for(int i=0;i<=n;i++)
        f[i].real=(double)a[i];
    for(int i=0;i<=m;i++){
        g[i].real=(double)b[i];
        a[i]+=b[i];
        b[i]=0;
    }
    lena=max(n,m);
    FFT(f,len,1);FFT(g,len,1);
    for(int i=0;i<=len;i++)
        f[i]=f[i]*g[i];
    FFT(f,len,-1);
    for(int i=0;i<=n+m;i++)
        ans[i]+=(int)(f[i].real/len+0.5);
    for(int i=0;i<len;i++)
        f[i].real=f[i].imaginary=g[i].real=g[i].imaginary=0.0;
    return;
}
void getroot(int u,int fa){
    sz[u]=1;
    maxx[u]=0;
    for(int i=h[u];i;i=ne[i]){
        if(e[i]==fa||vis[e[i]])
            continue;
        getroot(e[i],u);
        sz[u]+=sz[e[i]];
        maxx[u]=max(maxx[u],sz[e[i]]);
    }
    maxx[u]=max(maxx[u],sum-maxx[u]);
    if(maxx[root]>maxx[u]){
        root=u;
    }
    return;
}

void getdis(int u,int fa){
    b[dis[u]]++;
    if(lenb<dis[u])
        lenb=dis[u];
    for(int i=h[u];i;i=ne[i]){
        if(e[i]==fa||vis[e[i]])
            continue;
        dis[e[i]]=dis[u]+cst[i];
        getdis(e[i],u);
    }
}

struct Son {
    int v,c,d;
    bool operator<(const Son &b) const {
        return d < b.d;
    }
} sons[maxn];

void getdep(int u,int fa,int dep){
    maxdep=max(maxdep,dep);
    for(int i=h[u];i;i=ne[i]){
        if(vis[u]||e[i]==fa) continue;
        getdep(e[i],u,dep+cst[i]);
    }
}

void clac(int u){
    a[0]=1;lena=1;tot=0;
    for(int i=h[u];i;i=ne[i]){
        if(vis[e[i]]) continue;
        maxdep=0;
        getdep(e[i],u,cst[i]);
        sons[tot++]=(Son){e[i],cst[i],maxdep};
    }
    sort(sons,sons+tot);
    for(int i=0;i<tot;i++){
        int v=sons[i].v,w=sons[i].c;
        lenb=-1;
        dis[v]=w;
        getdis(v,u);
        work(lena,lenb);
    }
    for(int i=0;i<=lena;i++){
        a[i]=0;
    }
    return;
}

void solve(int u){
    vis[u]=true;
    clac(u);
    for(int i=h[u];i;i=ne[i]){
        if(vis[e[i]]) continue;
        sum=sz[e[i]];
        root=0;
        getroot(e[i],0);
        solve(root);
    }
    return;
}

using namespace IO;
int main(){
    srand(time(0));
    int n,m,x,y,z,k;
    IO::read(n);
    read(m);
    for(int i=1;i<n;i++){
        read(x);
        read(y);
        read(z);
        add(x,y,z);
    }
    sum=n;
    root=0;
    maxx[0]=INF;
    getroot(1,0);
    solve(root);
    for(int i=1;i<=200000;i++){
        ans[i]+=ans[i-1];
    }
    while(m--){
        read(k);
        k=lower_bound(ans,ans+200001,k)-ans;
        printf("%d\n",k);
    }
    return 0;
} 
全部评论
这样复杂度是错的啊,不知道怎么能过的
点赞 回复 分享
发布于 2021-01-11 13:04

相关推荐

昨天 11:07
河南大学 Java
宇宙厂 测开 n*15
丘丘给个offer:有后选后
点赞 评论 收藏
分享
美丽的查理斯不讲武德:包kpi的啊,感觉虾皮一点hc都没有
点赞 评论 收藏
分享
耀孝女:就是你排序挂了
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务