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; }
剩余的分数难度较大 ,留个坑吧

浙公网安备 33010602011771号