csp-s模拟10
10.1
闲话
- 详见 【闲话】高一上运动会 。
- 开完运动会就放假了,回家颓。
- 晚上和家长谈了下后面的集训安排。
做题纪要
10.2
闲话
- 起床后和家长谈了下后面的集训安排。然后把英语作业剩下的抄完了;数学作业还剩两个大题,抄的过程中怀疑自己是否真的学过基本不等式对数的放缩。
- 下午接着颓。
- 详见 2024 CSP-S 游记 10.2 。
- 详见 【闲话】高一上运动会 。
做题纪要
10.3
闲话
- 返校后分别去宿舍和教室收拾了下东西,然后就去机房了。
- 详见 2024 CSP-S 游记 10.3 。
- 临近 \(18:00\) 时 \(huge\) 突然进来跟我们说他跟高二的说让下去活动 \(20 \min\) ,问我们想不想下去,但是只能在科教馆附近(至远到超市或菜园子),遂跟着下去了。在楼下转悠的过程中看见了 @chancelong ,和其交流过程中得知了他们自愿留校的事情(我们初三的时候也有这个政策,但学生没有执行下去),说今年我们和高二的怎么说也得超过他们那一届,不然再过几年 \(HZOI\) 就真的完蛋了;然后他问了下今年零基础生奥的人数,说今年 \(HZ\) 生奥考得也不咋样,学校肯定得想办法把成绩拉回去,信奥估计就没这个福气了;我又问了下为啥没在运动会彩排及开幕式上看见他,于是便有了 【闲话】高一上运动会 中的片段;他走之前跟我说他假期要写魔怔闲话,让我一定要看。
- \(huge\) 说手机等人齐了再收,但晚上临下课时 \(miaomiao\) 也没收(估计是以为 \(huge\) 收了?)。
- 晚上 @wang54321 “操纵” @xrlong 刷博客园的评论,被 \(huge\) 全程窥屏并关机了,然后 \(huge\) 就进来 \(D\) 我们,说我们想刷论坛回家刷去,刚才让下去活动已经很通融了,怎么现在状态还怎么差,并声称他刚才关了两个人的电脑,但最后都没找到了另一个被关机的人。
- 晚休 \(huge\) 查宿。
做题纪要
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
闲话
- 上午 \(7:40 \sim 11:40\) \(miaomiao\) 安排了一场模拟赛。
- 到中午吃饭的时候手机还是没收。
- 下午 @HANGRY_sol 在手机充电过程中忘关机了,然后突然就有电话打了过来,接着就被 \(miaomiao\) 发现了,于是 \(miaomiao\) 就想起来我们手机还没收。交手机的时候问 \(miaomiao\) 笔记本电脑用不用交,他说放电脑机箱旁边就行,遂没交电脑。
- 吃晚饭的时候发现西藏班的进校了。
- 晚上化奥教练查宿。
做题纪要
luogu P4211 [LNOI2014] LCA
-
考虑点分树。
-
对于点分树上经过分治中心 \(x\) 的路径 \(u \to v\) ,若 \(\operatorname{LCA}(x,u)=x\) 则 \(\operatorname{LCA}(u,v)\) 一定在 \(x \to v\) 的路径上,处理出每个点与分治中心的 \(\operatorname{LCA}\) 的深度做前缀和即可;否则 \(\operatorname{LCA}(u,v)\) 一定在 \(u \to x\) 的路径上,二分统计合法点的数量即可。
点击查看代码
const ll p=201314; struct node { ll nxt,to; }e[100010]; ll head[100010],cnt=0; void add(ll u,ll v) { cnt++; e[cnt].nxt=head[u]; e[cnt].to=v; head[u]=cnt; } struct LCA { ll siz[100010],fa[100010],dep[100010],son[100010],top[100010]; 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) { 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 dep[x]+dep[y]-2*dep[lca(x,y)]; } }L; struct SMT { struct quality { ll val,sum; bool operator < (const quality &another) const { return val<another.val; } }; vector<quality>e[100010]; 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[100010],weight[100010],vis[100010],fa[100010],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,x,L.dep[x]); for(ll rt=x;fa[rt]!=0;rt=fa[rt]) { T[0].update(fa[rt],x,L.dep[L.lca(fa[rt],x)]); T[1].update(rt,x,L.dep[L.lca(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]) { if(L.lca(x,fa[rt])==fa[rt]) { ans=(ans+T[0].query_sum(fa[rt],l,r)-T[1].query_sum(rt,l,r))%p; } else { ans=(ans+L.dep[L.lca(x,fa[rt])]*(T[0].query_siz(fa[rt],l,r)-T[0].query_siz(rt,l,r))%p)%p; } } return ans; } }D; int main() { ll n,m,u,v,x,l,r,i; cin>>n>>m; for(i=2;i<=n;i++) { cin>>u; u++; v=i; add(u,v); add(v,u); } 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>>l>>r>>x; l++; r++; x++; cout<<D.query(x,l,r)<<endl; } return 0; }
-
由 \(dis_{u,v}=dis_{rt,u}+dis_{rt,v}-2*dis_{rt,\operatorname{LCA}(u,v)}\) 移项得 \(dis_{rt,\operatorname{LCA}(u,v)}=\frac{dis_{rt,u}+dis_{rt,v}-dis_{u,v}}{2}\) ,接着做法同 luogu P3241 [HNOI2015] 开店。
点击查看代码
const ll p=201314; struct node { ll nxt,to; }e[100010]; ll head[100010],sum[100010],cnt=0; void add(ll u,ll v) { cnt++; e[cnt].nxt=head[u]; e[cnt].to=v; head[u]=cnt; } struct LCA { ll siz[100010],fa[100010],dep[100010],son[100010],top[100010]; 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) { 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 dep[x]+dep[y]-2*dep[lca(x,y)]; } }L; struct SMT { struct quality { ll val,sum; bool operator < (const quality &another) const { return val<another.val; } }; vector<quality>e[100010]; 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[100010],weight[100010],vis[100010],fa[100010],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,x,0); for(ll rt=x;fa[rt]!=0;rt=fa[rt]) { T[0].update(fa[rt],x,L.get_dis(fa[rt],x)); T[1].update(rt,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 (L.dep[x]*(r-l+1)+sum[r]-sum[l-1]-ans)/2%p; } }D; int main() { ll n,m,u,v,x,l,r,i; cin>>n>>m; for(i=2;i<=n;i++) { cin>>u; u++; v=i; add(u,v); add(v,u); } L.init(); D.init(n); for(i=1;i<=n;i++) { sum[i]=sum[i-1]+L.dep[i]; D.update(i); } T[0].init(n); T[1].init(n); for(i=1;i<=m;i++) { cin>>l>>r>>x; l++; r++; x++; cout<<D.query(x,l,r)<<endl; } return 0; }
P294. 挤压
P295. 工地难题
- 弱化版: Gym103428M 810975
- 详见 冲刺CSP联训模拟2 T2 P295. 工地难题 。
P296. 星空遗迹
- 弱化版: QOJ 8046. Rock-Paper-Scissors Pyramid | Gym104065M Rock-Paper-Scissors Pyramid
- 详见 冲刺CSP联训模拟2 T3 P296. 星空遗迹 。
10.5
闲话
- \(miaomiao\) 说今天没有模拟赛,所以做 \(Vjudge\) 专题。
- 中午吃饭的时候遇到了 @xuany | @midsu ,并与 @xrlong 和 @wkh2008 探讨他是 @xuany 还是 @midsu 还是 @Rolling_star 。
- 吃完午饭回宿舍的路上看见德育主任和生物老师(貌似是某班班主任加年级干事)进高二宿舍楼了,可能是因为西藏班的也住在里面(?)。
- 午休物理和数学教练查宿。
- 晚上临下课的时候 \(feifei\) 进来跟我们说明天早上有体活,但是我现在忘了他说让几点到机房。
- 晚休 \(field\) 查宿(甚至还在下午问我们宿舍在哪里,然后就透露了学校那边让教练查宿的情况)。
做题纪要
luogu P6492 [COCI2010-2011#6] STEP
luogu P7735 [NOI2021] 轻重边
CF718C Sasha and Array
CF19D Points
CF946G Almost Increasing Array
[ABC374A] Takahashi san 2
-
基础字符串。
点击查看代码
int main() { int n; char s[50]; scanf("%s",s+1); n=strlen(s+1); if(s[n-2]=='s'&&s[n-1]=='a'&&s[n]=='n') { cout<<"Yes"<<endl; } else { cout<<"No"<<endl; } return 0; }
[ABC374B] Unvarnished Report
-
循环结构。
点击查看代码
char s[150],t[150]; int main() { int n,m,i,ans=0; scanf("%s%s",s+1,t+1); n=strlen(s+1); m=strlen(t+1); for(i=1;i<=max(n,m);i++) { if(s[i]!=t[i]) { ans=i; break; } } cout<<ans<<endl; return 0; }
[ABC374C] Separated Lunch
-
超大背包但不需要 \(meet in middle\) 。
点击查看代码
ll a[20],ans=0x7f7f7f7f; void dfs(ll pos,ll n,ll sum1,ll sum2) { if(pos==n+1) { ans=min(ans,max(sum1,sum2)); } else { dfs(pos+1,n,sum1+a[pos],sum2); dfs(pos+1,n,sum1,sum2+a[pos]); } } int main() { ll n,i; cin>>n; for(i=1;i<=n;i++) { cin>>a[i]; } dfs(1,n,0,0); cout<<ans<<endl; return 0; }
[ABC374D] Laser Marking
-
模拟。
点击查看代码
int a[10],b[10],c[10],d[10],vis[20],p[20]; double s,t,ans=0x7f7f7f7f; double work(double x1,double y1,double x2,double y2) { return sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1)); } int x(int p) { return p%2==0?a[p/2+1]:c[p/2+1]; } int y(int p) { return p%2==0?b[p/2+1]:d[p/2+1]; } void dfs(int pos,int n,int pre) { if(pos==2*n) { double sum=work(0,0,x(p[1]),y(p[1]))/s; for(int i=2;i<=2*n;i++) { if(i%2==1) { sum+=work(x(p[i-1]),y(p[i-1]),x(p[i]),y(p[i]))/s; } else { sum+=work(x(p[i-1]),y(p[i-1]),x(p[i]),y(p[i]))/t; } } ans=min(ans,sum); return; } else { if(vis[pre^1]==1) { for(int i=0;i<=2*n-1;i++) { if(vis[i]==0) { vis[i]=1; p[pos+1]=i; dfs(pos+1,n,i); vis[i]=0; } } } else { vis[pre^1]=1; p[pos+1]=pre^1; dfs(pos+1,n,pre^1); vis[pre^1]=0; } } } int main() { int n,i; cin>>n>>s>>t; for(i=1;i<=n;i++) { cin>>a[i]>>b[i]>>c[i]>>d[i]; } for(i=0;i<=2*n-1;i++) { p[1]=i; vis[i]=1; dfs(1,n,i); vis[i]=0; } printf("%.8lf\n",ans); return 0; }
10.6
闲话
- 因为忘了 \(feifei\) 说早上几点到机房,所以起床后直接去机房了。
- 上午 \(7:40 \sim 12:10\) 打 accoders NOI 的 \(NOIP2024A\) 层模拟赛, \(8:00 \sim 12:00\) 打学校模拟赛。中途去厕所的路上看见 \(huge\) 和 \(feifei\) 已经把 \(CSP-J/S\) 第二轮的倒计时展牌贴在了墙上,还听见他们在吐槽学校的做工劣质。
- 吃午饭的时候遇见 @xuany 和 @chancelong 了。
- 下午因为有 Codeforces Round 977 (Div. 2, based on COMPFEST 16 - Final Round) ,所以 \(huge\) 进来问我们有没有打的,比赛结束后组织了对 \(C2\) 的讲题。
- 晚上讲学校模拟赛的中途被拉去讲 accoders NOI 的 \(NOIP2024A\) 层模拟赛(因为上午交题交太快了,吃晚饭时被 \(field\) 叫住要求讲 \(T1,T2\) ),把讲 \(T1\) 的任务交给 @wlesq 了,我只讲了 \(T2\) 。然后还有下午 \(CF\) 的讲题,但鉴于我们基本没打所以没去听。
- 晚休数奥和化奥教练查宿。
做题纪要
CF193D Two Segments
T1075. 邻面合并
10.7
闲话
- 上午 \(7:40 \sim 11:40\) 打 accoders NOI 的 \(NOIP2024A\) 层模拟赛。
- 高一剩下的学生上午都返校了,国庆假期集训结束了。
- 临吃午饭的时候 \(miaomiao\) 跟我们说接下来就开始停课集训了,早上跑完操就直接来机房,原语文/英语早读改成了奥赛早预备(可能 \(huge\) 或 \(feifei\) 哪天想起来就让我们上一次早读);现在就先去教室收拾下书桌,不然后面考试布置考场的时候就没时间收拾了;发的资料晚新闻我们出一个代表去班里拿,并分发给众人,保证每人都拿到自己的资料,别像上一届一样把资料拿回来就堆在机房,现在还在各处找这些资料。遂去教室把书包放到了教室里。
做题纪要
T1076. 光线追踪
P343. 五彩斑斓(colorful)
P344. 错峰旅行(travel)
P346. 量子隧穿问题(experiment)
luogu P2502 [HAOI2006] 旅行
10.8
闲话
- 侯操
- 听隔壁 \(1\) 部年级主任爆典。
- “特长生不是特权生,同样需要遵守学校的规章制度,不允许携带行李箱进校。”
- 上次我们还被德育主任 \(D\) “某些奥赛班的行李箱太多了”。
- “特长生的手机等电子产品一律上交班主任保管。”
- 特长生训练时一般是随身携带手机、耳机的,方便和教练实时联系。初二的时候好像也整过这个规定,但在下一次放假回来之后就得不到丁点儿的落实。
- “特长生不是特权生,同样需要遵守学校的规章制度,不允许携带行李箱进校。”
- 然后是 \(2\) 部颁发流动红旗,以前起码还是发奖状呢(尽管都没写班号),或许真是应了英语老师说的现在 \(HZ\) 各校区都在能节约就节约,现在已经免掉了为实验班学生翻印的教辅,语文、英语习字本印刷两次间的间隔也比之前长了不少。
- 听隔壁 \(1\) 部年级主任爆典。
- 早上跟着高二的一起去吃饭了(提前了 \(5 \min\) ),回到机房后就被告知以后每天上午 \(7:30\) 开打模拟赛,那提前下去吃饭就“合法”了。
- 上午 \(7:30 \sim 11:30\) 打学校模拟赛。
- 中午不管 \(feifei\) 跟高二说的 \(12:17\) 去吃饭,直接 \(12:00\) 去吃饭。
- 下午到机房后放 \(huge\) 的每日一歌《蜂鸟》,然后开始讲题。
- 晚上 \(feifei\) 因我们
闲聊讨论时间过长、声音过大,说他给隔壁已经实行了铃声分辨是否是讨论时间,我们这个机房之所以不放是因为我们比较听话,而且人比较少(实际上估计是因为我们已经适应了初中 \(bobo\) 散养的管理模式,突然接受 \(huge\) 的管理可能不太适应),让我们在讨论时间再去讨论。
做题纪要
luogu P5494 【模板】线段树分裂
-
线段树分裂板子。
- 线段树分裂实质上是线段树合并的逆过程。
- 线段树分裂只能维护有序的序列,常用于维护连续序列或动态权值线段树。
- 设要把一颗区间为 \([1,n]\) 的线段树分裂出 \([x,y]\) ,并新建一棵树。
- 从根节点开始递归分裂,当节点不存在时直接返回。
- 若 \([l,r]\) 和 \([x,y]\) 有交集时新建节点(非严格意义新建)。
- 若 \([x,y]\) 包含于 \([l,r]\) ,将当前节点连到新的树下面,并断掉这条旧边。
- 递归分裂左右子树后进行
pushup
。
- 单次分裂的时间复杂度为 \(O(\log n)\) 。空间复杂度为 \(O(m \log n)\) 。
- 当线段树分裂和合并同时存在时删除节点时需要清空其左右儿子及其他额外信息,且空间时间复杂度带 \(2\) 倍常数。
-
本题中因空间略小需要回收垃圾节点。
点击查看代码
ll a[200010]; struct SMT { ll root[200010],rt_sum; stack<ll>s; struct SegmentTree { ll ls,rs,sum; }tree[200010<<5]; #define lson(rt) (tree[rt].ls) #define rson(rt) (tree[rt].rs) ll build_rt() { ll rt; if(s.empty()==0) { rt=s.top(); s.pop(); } else { rt_sum++; rt=rt_sum; } lson(rt)=rson(rt)=tree[rt].sum=0; return rt; } void del_rt(ll &rt) { lson(rt)=rson(rt)=tree[rt].sum=0; s.push(rt); rt=0;//清空集合(本题中因为保证 t 不会再出现所以这一行可以省略) } void pushup(ll rt) { tree[rt].sum=tree[lson(rt)].sum+tree[rson(rt)].sum; } void build(ll &rt,ll l,ll r) { rt=build_rt(); if(l==r) { tree[rt].sum=a[l]; return; } ll mid=(l+r)/2; build(lson(rt),l,mid); build(rson(rt),mid+1,r); pushup(rt); } void update(ll &rt,ll l,ll r,ll pos,ll val) { rt=(rt==0)?build_rt():rt; if(l==r) { tree[rt].sum+=val; return; } ll mid=(l+r)/2; if(pos<=mid) { update(lson(rt),l,mid,pos,val); } else { update(rson(rt),mid+1,r,pos,val); } pushup(rt); } void merge(ll &rt1,ll &rt2,ll l,ll r) { if(rt1==0||rt2==0) { rt1+=rt2;//强制删掉 rt2 return; } if(l==r) { tree[rt1].sum+=tree[rt2].sum; del_rt(rt2); return; } ll mid=(l+r)/2; merge(lson(rt1),lson(rt2),l,mid); merge(rson(rt1),rson(rt2),mid+1,r); del_rt(rt2); pushup(rt1); } void split(ll &rt1,ll &rt2,ll l,ll r,ll x,ll y) { if(rt1==0) { return; } rt2=(rt2==0)?build_rt():rt2; if(x<=l&&r<=y) { tree[rt2]=tree[rt1];//连接到新树上 rt1=0;//断掉这条旧边 return; } ll mid=(l+r)/2; if(x<=mid) { split(lson(rt1),lson(rt2),l,mid,x,y); } if(y>mid) { split(rson(rt1),rson(rt2),mid+1,r,x,y); } pushup(rt1); pushup(rt2); } ll query(ll rt,ll l,ll r,ll x,ll y) { if(rt==0) { return 0; } if(x<=l&&r<=y) { return tree[rt].sum; } ll mid=(l+r)/2,ans=0; if(x<=mid) { ans+=query(lson(rt),l,mid,x,y); } if(y>mid) { ans+=query(rson(rt),mid+1,r,x,y); } return ans; } ll kth_min(ll rt,ll l,ll r,ll k) { if(l==r) { return (tree[rt].sum>=k)?l:-1; } ll mid=(l+r)/2; if(tree[lson(rt)].sum>=k) { return kth_min(lson(rt),l,mid,k); } else { return kth_min(rson(rt),mid+1,r,k-tree[lson(rt)].sum); } } }T; int main() { ll n,m,pos=1,pd,p,x,y,i; cin>>n>>m; for(i=1;i<=n;i++) { cin>>a[i]; } T.build(T.root[pos],1,n); for(i=1;i<=m;i++) { cin>>pd; if(pd==0) { cin>>p>>x>>y; pos++; T.split(T.root[p],T.root[pos],1,n,x,y); } if(pd==1) { cin>>p>>x; T.merge(T.root[p],T.root[x],1,n); } if(pd==2) { cin>>p>>x>>y; T.update(T.root[p],1,n,y,x); } if(pd==3) { cin>>p>>x>>y; cout<<T.query(T.root[p],1,n,x,y)<<endl; } if(pd==4) { cin>>p>>x; cout<<T.kth_min(T.root[p],1,n,x)<<endl; } } return 0; }
T1042. ants
[AGC010C] Cleaning
T1072. 购物
10.9
闲话
- 侯操时的动员中声称今天是 \(10.8\) 。因昨天早操两个体委都还在外面机构里集训,没有返校,而且把体委服都带回家了,所以实际跑操时的候补体委没有穿体委服,所以今天需要加圈(年级部规定不穿体委服就加圈)。跑完正常的一圈后尝试和班主任、年级干事交涉能不能不跑加的一圈,得到的回复是不能。
- 上午 \(7:30 \sim 11:30\) 打 accoders NOI 的模拟赛。快 \(10:30\) 时零基础的来上奥赛课,他们遂被赶去 \(miaomiao\) 跟学校申请占用的信息课机房,路过时听见是 \(field\) 在给他们讲课。
- 下午到机房后放 @HaneDaniko 每日一歌《Echoism》,然后开始讲题。
- 下午看见 \(feifei,field,huge\) 突然穿得非常正式,从他们的谈话中得知他们要去开会。
- 临吃晚饭前 \(huge\) 进来跟我们说明天没有模拟赛,多校的安排是写 图论2(tarjan,2-SAT,欧拉路,竞赛图,图的性质,综合应用) 的题,并在明天晚上组织讨论,今天晚上和明天我们好好把模拟赛改改,另外明天我们要是没有自己的安排就遵照执行多校的安排,但我感觉里面没有一个是可做题,遂打算继续补 数据结构1 。
- 晚饭时直接跟着高二的 \(18:13\) 就去吃饭了。
做题纪要
luogu P1010 [NOIP1998 普及组] 幂次方
P356.子串的子串
P357.魔法咒语
P358.表达式
10.10
闲话
做题纪要
luogu P2824 [HEOI2016/TJOI2016] 排序
-
考虑将每一个数单独插入一棵权值线段树里,珂朵莉树记录一段区间升序/降序。
-
于是区间排序转化为权值线段树合并、分裂即可。
点击查看代码
int a[100010]; struct SMT { int root[100010],rt_sum; struct SegmentTree { int ls,rs,sum; }tree[100010<<6]; #define lson(rt) (tree[rt].ls) #define rson(rt) (tree[rt].rs) int build_rt() { rt_sum++; lson(rt_sum)=rson(rt_sum)=tree[rt_sum].sum=0; return rt_sum; } void del_rt(int &rt) { lson(rt)=rson(rt)=tree[rt].sum=0; rt=0; } void pushup(int rt) { tree[rt].sum=tree[lson(rt)].sum+tree[rson(rt)].sum; } void update(int &rt,int l,int r,int pos,int val) { rt=(rt==0)?build_rt():rt; if(l==r) { tree[rt].sum+=val; return; } int mid=(l+r)/2; if(pos<=mid) { update(lson(rt),l,mid,pos,val); } else { update(rson(rt),mid+1,r,pos,val); } pushup(rt); } void merge(int &rt1,int &rt2,int l,int r) { if(rt1==0||rt2==0) { rt1+=rt2; return; } if(l==r) { tree[rt1].sum+=tree[rt2].sum; del_rt(rt2); return; } int mid=(l+r)/2; merge(lson(rt1),lson(rt2),l,mid); merge(rson(rt1),rson(rt2),mid+1,r); del_rt(rt2); pushup(rt1); } void split(int &rt1,int &rt2,int l,int r,int k,int pd) { if(rt1==0||tree[rt1].sum==k) { return; } rt2=(rt2==0)?build_rt():rt2; tree[rt2].sum=tree[rt1].sum-k; tree[rt1].sum=k; int mid=(l+r)/2; if(pd==1) { if(k<=tree[rson(rt1)].sum) { split(rson(rt1),rson(rt2),mid+1,r,k,pd); lson(rt2)=lson(rt1); lson(rt1)=0; } else { split(lson(rt1),lson(rt2),l,mid,k-tree[rson(rt1)].sum,pd); } } else { if(k<=tree[lson(rt1)].sum) { split(lson(rt1),lson(rt2),l,mid,k,pd); rson(rt2)=rson(rt1); rson(rt1)=0; } else { split(rson(rt1),rson(rt2),mid+1,r,k-tree[lson(rt1)].sum,pd); } } pushup(rt1); pushup(rt2); } int query(int rt,int l,int r,int k) { if(l==r) { return (tree[rt].sum>=k)?l:-1; } int mid=(l+r)/2; if(tree[lson(rt)].sum>=k) { return query(lson(rt),l,mid,k); } else { return query(rson(rt),mid+1,r,k-tree[lson(rt)].sum); } } }T; struct ODT { struct node { int l,r; mutable int col; bool operator < (const node &another) const { return l<another.l; } }; set<node>s; void init(int n) { for(int i=1;i<=n;i++) { s.insert((node){i,i,0}); } } set<node>::iterator split(int pos,int n) { set<node>::iterator it=s.lower_bound((node){pos,0,0}); if(it!=s.end()&&it->l==pos) { return it; } it--; if(it->r<pos) { return s.end(); } int l=it->l,r=it->r,col=it->col; s.erase(it); T.split(T.root[l],T.root[pos],1,n,(pos-1)-l+1,col); s.insert((node){l,pos-1,col}); return s.insert((node){pos,r,col}).first; } void assign(int l,int r,int col,int n) { set<node>::iterator itr=split(r+1,n),itl=split(l,n); itl++; for(set<node>::iterator it=itl;it!=itr;it++) { T.merge(T.root[l],T.root[it->l],1,n); } itl--; s.erase(itl,itr); s.insert((node){l,r,col}); } int query(int pos,int n) { split(pos+1,n); split(pos,n); return T.query(T.root[pos],1,n,1); } }O; int main() { int n,m,pd,l,r,i; cin>>n>>m; for(i=1;i<=n;i++) { cin>>a[i]; T.update(T.root[i],1,n,a[i],1); } O.init(n); for(i=1;i<=m;i++) { cin>>pd>>l>>r; O.assign(l,r,pd,n); } cin>>l; cout<<O.query(l,n)<<endl; return 0; }
CF558E A Simple Task
-
将字符离散成 \([1,n]\) 的排列,然后就和 luogu P2824 [HEOI2016/TJOI2016] 排序 一样了。
点击查看代码
pair<char,int>a[100010],b[100010]; struct SMT { int root[100010],rt_sum; struct SegmentTree { int ls,rs,sum; }tree[100010<<6]; #define lson(rt) (tree[rt].ls) #define rson(rt) (tree[rt].rs) int build_rt() { rt_sum++; lson(rt_sum)=rson(rt_sum)=tree[rt_sum].sum=0; return rt_sum; } void del_rt(int &rt) { lson(rt)=rson(rt)=tree[rt].sum=0; rt=0; } void pushup(int rt) { tree[rt].sum=tree[lson(rt)].sum+tree[rson(rt)].sum; } void update(int &rt,int l,int r,int pos,int val) { rt=(rt==0)?build_rt():rt; if(l==r) { tree[rt].sum+=val; return; } int mid=(l+r)/2; if(pos<=mid) { update(lson(rt),l,mid,pos,val); } else { update(rson(rt),mid+1,r,pos,val); } pushup(rt); } void merge(int &rt1,int &rt2,int l,int r) { if(rt1==0||rt2==0) { rt1+=rt2; return; } if(l==r) { tree[rt1].sum+=tree[rt2].sum; del_rt(rt2); return; } int mid=(l+r)/2; merge(lson(rt1),lson(rt2),l,mid); merge(rson(rt1),rson(rt2),mid+1,r); del_rt(rt2); pushup(rt1); } void split(int &rt1,int &rt2,int l,int r,int k,int pd) { if(rt1==0||tree[rt1].sum==k) { return; } rt2=(rt2==0)?build_rt():rt2; tree[rt2].sum=tree[rt1].sum-k; tree[rt1].sum=k; int mid=(l+r)/2; if(pd==0) { if(k<=tree[rson(rt1)].sum) { split(rson(rt1),rson(rt2),mid+1,r,k,pd); lson(rt2)=lson(rt1); lson(rt1)=0; } else { split(lson(rt1),lson(rt2),l,mid,k-tree[rson(rt1)].sum,pd); } } else { if(k<=tree[lson(rt1)].sum) { split(lson(rt1),lson(rt2),l,mid,k,pd); rson(rt2)=rson(rt1); rson(rt1)=0; } else { split(rson(rt1),rson(rt2),mid+1,r,k-tree[lson(rt1)].sum,pd); } } pushup(rt1); pushup(rt2); } int query(int rt,int l,int r,int k) { if(l==r) { return (tree[rt].sum>=k)?l:-1; } int mid=(l+r)/2; if(tree[lson(rt)].sum>=k) { return query(lson(rt),l,mid,k); } else { return query(rson(rt),mid+1,r,k-tree[lson(rt)].sum); } } }T; struct ODT { struct node { int l,r; mutable int col; bool operator < (const node &another) const { return l<another.l; } }; set<node>a; void init(int n) { for(int i=1;i<=n;i++) { a.insert((node){i,i,0}); } } set<node>::iterator split(int pos,int n) { set<node>::iterator it=a.lower_bound((node){pos,0,0}); if(it!=a.end()&&it->l==pos) { return it; } it--; if(it->r<pos) { return a.end(); } int l=it->l,r=it->r,col=it->col; a.erase(it); T.split(T.root[l],T.root[pos],1,n,(pos-1)-l+1,col); a.insert((node){l,pos-1,col}); return a.insert((node){pos,r,col}).first; } void assign(int l,int r,int col,int n) { set<node>::iterator itr=split(r+1,n),itl=split(l,n); itl++; for(set<node>::iterator it=itl;it!=itr;it++) { T.merge(T.root[l],T.root[it->l],1,n); } itl--; a.erase(itl,itr); a.insert((node){l,r,col}); } }O; int main() { int n,m,l,r,pd,i; cin>>n>>m; for(i=1;i<=n;i++) { cin>>a[i].first; a[i].second=i; b[i]=a[i]; } sort(b+1,b+1+n); b[0].second=unique(b+1,b+1+n)-(b+1); for(i=1;i<=n;i++) { T.update(T.root[i],1,n,lower_bound(b+1,b+1+b[0].second,a[i])-b,1); } O.init(n); for(i=1;i<=m;i++) { cin>>l>>r>>pd; O.assign(l,r,pd,n); } for(i=1;i<=n;i++) { O.split(i,n); } for(i=1;i<=n;i++) { cout<<b[T.query(T.root[i],1,n,1)].first; } return 0; }
luogu P3812 【模板】线性基
-
线性基板子。
点击查看代码
#include<bits/stdc++.h> using namespace std; #define ll long long #define ull unsigned long long #define sort stable_sort #define endl '\n' ll d[70]; void insert(ll x) { for(ll i=60;i>=0;i--) { if((x>>i)&1) { if(d[i]==0) { d[i]=x; break; } x^=d[i]; } } } int main() { ll n,x,ans=0,i; cin>>n; for(i=1;i<=n;i++) { cin>>x; insert(x); } for(i=60;i>=0;i--) { ans=max(ans,ans^d[i]); } cout<<ans<<endl; return 0; } /* #include<bits/stdc++.h> using namespace std; #define ll long long #define ull unsigned long long #define sort stable_sort #define endl '\n' ll x[70],d[70]; ll gauss(ll n) { ll row=1; for(ll i=1;i<=n;i++) { d[i]=x[i]; } for(ll col=60;col>=0&&row<=n;col--) { for(ll i=row;i<=n;i++) { if((d[i]>>col)&1) { swap(d[row],d[i]); break; } } if((d[row]>>col)&1) { for(ll i=1;i<=n;i++) { if(i!=row&&((d[i]>>col)&1)) { d[i]^=d[row]; } } row++; } } row--; return row; } int main() { ll n,row,ans=0,i; cin>>n; for(i=1;i<=n;i++) { cin>>x[i]; } row=gauss(n); for(i=1;i<=row;i++) { ans^=d[i]; } cout<<ans<<endl; return 0; } */
T3673. 欧几里得的噩梦
CF1956F Nene and the Passing Game
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; }
-
[ABC366G] XOR Neighbors
CF341D Iahub and Xors
本文来自博客园,作者:hzoi_Shadow,原文链接:https://www.cnblogs.com/The-Shadow-Dragon/p/18452249,未经允许严禁转载。
版权声明:本作品采用 「署名-非商业性使用-相同方式共享 4.0 国际」许可协议(CC BY-NC-SA 4.0) 进行许可。