CSP/NOIP新赛制内部挑战赛2 C. 哲学树

 

 

 

 

 

 

sub1 (25pts)

暴力从x走到y,如果在某个点思考获得的智慧为正,就累加进答案


时间复杂度:O(Q*dep+n)

dep为树深度,当树随机生成时,期望为log n

 

开long long !!

 

代码

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
int n,m,type,dep[maxn],f[maxn],head[maxn],cnt;
long long a[maxn],v[maxn];
struct edge
{
    int to,nxt;
}e[maxn<<1];
void add(int x,int y)
{
    e[++cnt].to=y;
    e[cnt].nxt=head[x];
    head[x]=cnt;
}
void dfs(int u,int fa)
{
    f[u]=fa; dep[u]=dep[fa]+1;
    for(int i=head[u];i;i=e[i].nxt)
    {
        int to=e[i].to;
        if(to==fa) continue;
        dfs(to,u);
    }
}
vector <int> pa,pb;
void getpath(int x,int y)
{
    while(dep[x]>dep[y])
    {
        pa.push_back(x);
        x=f[x];
    }
    while(dep[x]<dep[y])
    {
        pb.push_back(y);
        y=f[y];
    }
    if(x==y)
    {
        pa.push_back(x);
        return;
    }
    while(f[x]!=f[y])
    {
        pa.push_back(x);
        pb.push_back(y);
        x=f[x]; y=f[y];
    }
    pa.push_back(x);
    pa.push_back(f[x]);
    pa.push_back(y);
}
int main()
{
    freopen("a.in","r",stdin);
    freopen("a.out","w",stdout);
    int x,y,z;
    scanf("%d",&x);
    scanf("%d%d%d",&n,&m,&type);
    for(int i=1;i<n;i++)
    {
        scanf("%d%d",&x,&y);
        add(x,y); add(y,x);
    }
    dfs(1,0);
    for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
    for(int i=1;i<=n;i++) scanf("%lld",&v[i]);
    long long ans=0;
    for(int i=1;i<=m;i++)
    {
        ans=0;
        pa.clear(); pb.clear();
        scanf("%d%d%d",&x,&y,&z);
        getpath(x,y);
        for(int j=pb.size()-1;j>=0;j--) pa.push_back(pb[j]);
        for(int j=0;j<pa.size();j++)
            if(1LL*(z+j)*v[pa[j]]+a[pa[j]]>0)
                ans+=1LL*(z+j)*v[pa[j]]+a[pa[j]];
        printf("%lld\n",ans);
    }
    return 0;
}

 

Sub2 extra 15pts

v[i]=0 的部分可以用树上差分来解决

时间复杂度O(Q*log N)

 

代码

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
int n,m,type,dep[maxn],f[maxn],head[maxn],cnt,father[maxn][20];
long long a[maxn],v[maxn],dis[maxn];
struct edge
{
    int to,nxt;
}e[maxn<<1];
void add(int x,int y)
{
    e[++cnt].to=y;
    e[cnt].nxt=head[x];
    head[x]=cnt;
}
void dfs(int u,int fa)
{
    dis[u]=dis[fa]; father[u][0]=fa;
    if(a[u]>0) dis[u]+=a[u];
    f[u]=fa; dep[u]=dep[fa]+1;
    for(int i=head[u];i;i=e[i].nxt)
    {
        int to=e[i].to;
        if(to==fa) continue;
        dfs(to,u);
    }
}
vector <int> pa,pb;
void getpath(int x,int y)
{
    while(dep[x]>dep[y])
    {
        pa.push_back(x);
        x=f[x];
    }
    while(dep[x]<dep[y])
    {
        pb.push_back(y);
        y=f[y];
    }
    if(x==y)
    {
        pa.push_back(x);
        return;
    }
    while(f[x]!=f[y])
    {
        pa.push_back(x);
        pb.push_back(y);
        x=f[x]; y=f[y];
    }
    pa.push_back(x);
    pa.push_back(f[x]);
    pa.push_back(y);
}
int LCA(int x,int y)
{
    if(dep[x]<dep[y]) swap(x,y);
    for(int i=19;i>=0;i--)
        if(dep[father[x][i]]>=dep[y])
            x=father[x][i];
    if(x==y) return x;
    for(int i=19;i>=0;i--)
        if(father[x][i]!=father[y][i])
            x=father[x][i],y=father[y][i];
    return father[x][0];
}
void init_father()
{
    for(int i=1;i<=n;i++)    
        for(int j=1;j<=19;j++)
            father[i][j]=father[father[i][j-1]][j-1];
}
void solve()
{
    int x,y,z;
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&x,&y,&z);
        int lca=LCA(x,y);
        long long ans=dis[x]+dis[y]-dis[lca]-dis[f[lca]];
        printf("%lld\n",ans);
    }    
}
int main()
{
    freopen("a.in","r",stdin);
    freopen("a.out","w",stdout);
    int x,y,z;
    scanf("%d",&x);
    scanf("%d%d%d",&n,&m,&type);
    for(int i=1;i<n;i++)
    {
        scanf("%d%d",&x,&y);
        add(x,y); add(y,x);
    }
    for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
    dfs(1,0); int flag=0;
    for(int i=1;i<=n;i++)
    {
        scanf("%lld",&v[i]);
        if(v[i]) flag=1;
    }
    long long ans=0;
    if(!flag)
    {
        init_father();
        solve();
        return 0;
    }
    for(int i=1;i<=m;i++)
    {
        ans=0;
        pa.clear(); pb.clear();
        scanf("%d%d%d",&x,&y,&z);
        getpath(x,y);
        for(int j=pb.size()-1;j>=0;j--) pa.push_back(pb[j]);
        for(int j=0;j<pa.size();j++)
            if(1LL*(z+j)*v[pa[j]]+a[pa[j]]>0)
                ans+=1LL*(z+j)*v[pa[j]]+a[pa[j]];
        printf("%lld\n",ans);
    }
    return 0;
}

 

剩余的分数难度较大 ,留个坑吧

 

posted @ 2020-11-27 16:52  andyc_03  阅读(113)  评论(0)    收藏  举报