10.1
闲话
做题纪要
10.2
闲话
做题纪要
10.3
闲话
做题纪要
luogu P3241 [HNOI2015] 开店
-
不难发现两个点在点分树上的 \(\operatorname{LCA}\) 是一个求距离的好的分割点,考虑点分树。
-
暂且不考虑 \([l,r]\) 的限制,因为只是一个限制范围的查找。
-
设 \(siz_{x}\) 表示点分树上以 \(x\) 为根的子树大小, \(sum_{0/1,x}\) 表示点分数上以 \(x\) 为根的子树内的所有节点到 \(x\) / \(x\) 在点分树上的父亲节点的距离和。
-
设当前开店节点为 \(x\) ,在点分树上跳到了 \(rt\) 。
-
仍考虑枚举 \(\operatorname{LCA}\) ,除去 \(rt\) 方向上的贡献,此时对答案产生的贡献为 \(sum_{0,fa_{rt}}-sum_{1,rt}+(siz_{fa_{rt}}-siz_{rt}) \times dis_{x,fa_{rt}}\) 。
-
对于年龄 \(\in [l,r]\) 的限制,套一个支持单点插入、区间查询的数据结构即可。
-
离散化后使用动态开点线段树貌似空间还是会爆炸,又因为没有修改操作,所以使用
vector
代替即可。具体地,原区间查询距离和转化为二分端点后的两个前缀和相减,原查询大小和转化为二分端点后两个端点相减。点击查看代码
struct node { ll nxt,to,w; }e[300010]; ll head[300010],a[300010],cnt=0; void add(ll u,ll v,ll w) { cnt++; e[cnt].nxt=head[u]; e[cnt].to=v; e[cnt].w=w; head[u]=cnt; } struct LCA { ll siz[300010],fa[300010],dep[300010],son[300010],top[300010],dis[300010]; void init() { dfs1(1,0); dfs2(1,1); } void dfs1(ll x,ll father) { siz[x]=1; fa[x]=father; dep[x]=dep[father]+1; for(ll i=head[x];i!=0;i=e[i].nxt) { if(e[i].to!=father) { dis[e[i].to]=dis[x]+e[i].w; dfs1(e[i].to,x); siz[x]+=siz[e[i].to]; son[x]=(siz[e[i].to]>siz[son[x]])?e[i].to:son[x]; } } } void dfs2(ll x,ll id) { top[x]=id; if(son[x]!=0) { dfs2(son[x],id); for(ll i=head[x];i!=0;i=e[i].nxt) { if(e[i].to!=fa[x]&&e[i].to!=son[x]) { dfs2(e[i].to,e[i].to); } } } } ll lca(ll u,ll v) { while(top[u]!=top[v]) { if(dep[top[u]]>dep[top[v]]) { u=fa[top[u]]; } else { v=fa[top[v]]; } } return (dep[u]<dep[v])?u:v; } ll get_dis(ll x,ll y) { return dis[x]+dis[y]-2*dis[lca(x,y)]; } }L; struct SMT { struct quality { ll val,sum; bool operator < (const quality &another) const { return val<another.val; } }; vector<quality>e[300010]; void update(ll x,ll val,ll sum) { e[x].push_back((quality){val,sum}); } void init(ll n) { for(ll i=1;i<=n;i++) { sort(e[i].begin(),e[i].end()); for(ll j=1;j<e[i].size();j++) { e[i][j].sum+=e[i][j-1].sum; } } } ll query_sum(ll x,ll l,ll r) { l=lower_bound(e[x].begin(),e[x].end(),(quality){l,0})-e[x].begin(); r=upper_bound(e[x].begin(),e[x].end(),(quality){r,0})-e[x].begin()-1; ll ans=0; if(0<=r&&r<e[x].size()) { ans+=e[x][r].sum; } if(0<=l-1&&l-1<e[x].size()) { ans-=e[x][l-1].sum; } return ans; } ll query_siz(ll x,ll l,ll r) { l=lower_bound(e[x].begin(),e[x].end(),(quality){l,0})-e[x].begin(); r=upper_bound(e[x].begin(),e[x].end(),(quality){r,0})-e[x].begin()-1; return r-(l-1); } }T[2]; struct Divide_On_Tree { ll siz[300010],weight[300010],vis[300010],fa[300010],center=0; void init(ll n) { center=0; get_center(1,0,n); get_siz(center,0); build(center); } void get_center(ll x,ll fa,ll n) { siz[x]=1; weight[x]=0; for(ll i=head[x];i!=0;i=e[i].nxt) { if(e[i].to!=fa&&vis[e[i].to]==0) { get_center(e[i].to,x,n); siz[x]+=siz[e[i].to]; weight[x]=max(weight[x],siz[e[i].to]); } } weight[x]=max(weight[x],n-siz[x]); if(weight[x]<=n/2) { center=x; } } void get_siz(ll x,ll fa) { siz[x]=1; for(ll i=head[x];i!=0;i=e[i].nxt) { if(e[i].to!=fa&&vis[e[i].to]==0) { get_siz(e[i].to,x); siz[x]+=siz[e[i].to]; } } } void build(ll x) { vis[x]=1; for(ll i=head[x];i!=0;i=e[i].nxt) { if(vis[e[i].to]==0) { center=0; get_center(e[i].to,x,siz[e[i].to]); get_siz(center,0); fa[center]=x; build(center); } } } void update(ll x) { T[0].update(x,a[x],0); for(ll rt=x;fa[rt]!=0;rt=fa[rt]) { T[0].update(fa[rt],a[x],L.get_dis(fa[rt],x)); T[1].update(rt,a[x],L.get_dis(fa[rt],x)); } } ll query(ll x,ll l,ll r) { ll ans=T[0].query_sum(x,l,r); for(ll rt=x;fa[rt]!=0;rt=fa[rt]) { ans+=T[0].query_sum(fa[rt],l,r)-T[1].query_sum(rt,l,r); ans+=(T[0].query_siz(fa[rt],l,r)-T[0].query_siz(rt,l,r))*L.get_dis(fa[rt],x); } return ans; } }D; int main() { ll n,m,mod,u,v,w,x,l,r,ans=0,i; cin>>n>>m>>mod; for(i=1;i<=n;i++) { cin>>a[i]; } for(i=1;i<=n-1;i++) { cin>>u>>v>>w; add(u,v,w); add(v,u,w); } L.init(); D.init(n); for(i=1;i<=n;i++) { D.update(i); } T[0].init(n); T[1].init(n); for(i=1;i<=m;i++) { cin>>x>>l>>r; l=(l+ans)%mod; r=(r+ans)%mod; if(l>r) { swap(l,r); } ans=D.query(x,l,r); cout<<ans<<endl; } return 0; }
10.4
闲话
做题纪要
luogu P4211 [LNOI2014] LCA
-
考虑点分树。
-
对于点分树上经过分治中心 \(x\) 的路径 \(u \to v\) ,\(\operatorname{LCA}(u,v)\) 一定在 \(u \to x\) 或 \(x \to v\) 的路径上。
-
处理出每个点到分治中心的 \(\operatorname{LCA}\) 做前缀和即可。
点击查看代码
luogu P3345 [ZJOI2015] 幻想乡战略游戏
luogu P5311 [Ynoi2011] 成都七中
[ABC373F] Knapsack with Diminishing Values
- 暴力
-
分组背包写个常数小点的加 \(C++20\) 加手动开 \(O3\) 就过了(赛时直接把火车头粘上了),算下来 \(AT\) 神机能跑 \(1e10\) 。
点击查看代码
#include<bits/stdc++.h> #pragma GCC optimize(3) #pragma GCC target("avx") #pragma GCC optimize("Ofast") #pragma GCC optimize("inline") #pragma GCC optimize("-fgcse") #pragma GCC optimize("-fgcse-lm") #pragma GCC optimize("-fipa-sra") #pragma GCC optimize("-ftree-pre") #pragma GCC optimize("-ftree-vrp") #pragma GCC optimize("-fpeephole2") #pragma GCC optimize("-ffast-math") #pragma GCC optimize("-fsched-spec") #pragma GCC optimize("unroll-loops") #pragma GCC optimize("-falign-jumps") #pragma GCC optimize("-falign-loops") #pragma GCC optimize("-falign-labels") #pragma GCC optimize("-fdevirtualize") #pragma GCC optimize("-fcaller-saves") #pragma GCC optimize("-fcrossjumping") #pragma GCC optimize("-fthread-jumps") #pragma GCC optimize("-funroll-loops") #pragma GCC optimize("-fwhole-program") #pragma GCC optimize("-freorder-blocks") #pragma GCC optimize("-fschedule-insns") #pragma GCC optimize("inline-functions") #pragma GCC optimize("-ftree-tail-merge") #pragma GCC optimize("-fschedule-insns2") #pragma GCC optimize("-fstrict-aliasing") #pragma GCC optimize("-fstrict-overflow") #pragma GCC optimize("-falign-functions") #pragma GCC optimize("-fcse-skip-blocks") #pragma GCC optimize("-fcse-follow-jumps") #pragma GCC optimize("-fsched-interblock") #pragma GCC optimize("-fpartial-inlining") #pragma GCC optimize("no-stack-protector") #pragma GCC optimize("-freorder-functions") #pragma GCC optimize("-findirect-inlining") #pragma GCC optimize("-fhoist-adjacent-loads") #pragma GCC optimize("-frerun-cse-after-loop") #pragma GCC optimize("inline-small-functions") #pragma GCC optimize("-finline-small-functions") #pragma GCC optimize("-ftree-switch-conversion") #pragma GCC optimize("-foptimize-sibling-calls") #pragma GCC optimize("-fexpensive-optimizations") #pragma GCC optimize("-funsafe-loop-optimizations") #pragma GCC optimize("inline-functions-called-once") #pragma GCC optimize("-fdelete-null-pointer-checks") using namespace std; #define ll long long #define ull unsigned long long #define sort stable_sort #define endl '\n' ll w[3010],v[3010],f[2][3010]; int main() { ll n,m,ans=0,i,j,k; cin>>n>>m; for(i=1;i<=n;i++) { cin>>w[i]>>v[i]; } for(i=1;i<=n;i++) { for(j=1;j<=m;j++) { f[i&1][j]=f[(i-1)&1][j]; } for(k=1;k*w[i]<=m;k++) { for(j=k*w[i];j<=m;j++) { f[i&1][j]=max(f[i&1][j],f[(i-1)&1][j-k*w[i]]+k*v[i]-k*k); } } } for(i=1;i<=m;i++) { ans=max(ans,f[n&1][i]); } cout<<ans<<endl; return 0; }
-