高一上十月下旬日记
10.21
闲话
- 跑完操到机房后 \(feifei\) 又说今天没有早读任务,让我们自由安排,然后就去隔壁机房坐着了。遂颓《红楼梦》。
- 上午 \(7:30 \sim 11:30\) 打 accoders NOI 的模拟赛。临结束时 \(miaomiao\) 跟我们说也往 $ftp 里按正规考试传下文件,他要用 \(LemonLime\) 在本地评测。
- 下午放我的每日一歌《回到奥奇》; \(feifei\) 叫高二的去宣誓时还问了下 \(miaomiao\) 我们用不用去,\(miaomiao\) 说也让我们去;然后讲题。
做题纪要
P391. 岛屿
P392. 最短路
10.22
闲话
- 跑完操到机房后被 \(huge\) 拉去和隔壁机房一起宣誓了,然后 \(huge\) 又跟我们说了下早读的好处。又没有早读任务,遂颓《红楼梦》,期间 \(huge\) 来转的时候象征性地拿语文课本挡住了。
- 上午 \(7:30 \sim 11:30\) 打 accoders NOI 的模拟赛。
- 下午放 @DanhengYinyue 的每日一歌《Operation Fake Waves(赝波行动)》,然后和高二的一起宣誓,走的时候 \(huge\) 跟我们说今天还安排了写 树上问题 。
- 晚上因
讨论闲聊时间被 \(huge\) \(D\) 了。然后在下节课的讨论时间开始时 \(huge\) 跟我们说让我们活动活动,把想说的话都说完。 - 详见 2024 CSP-S 游记 10.22 。
做题纪要
P395. 冒泡排序
P396. 染色
P385. 区间 (interval)
luogu P5104 红包发红包
-
考虑求出前 \(k-1\) 个人抢完红包后剩的期望钱数 \(\frac{w}{2^{k-1}}\) ,和前 \(k\) 个人抢完红包后剩的期望钱数 \(\frac{w}{2^{k}}\) 相减得到第 \(k\) 个人抢到的期望钱数。
点击查看代码
const ll p=1000000007; ll qpow(ll a,ll b,ll p) { ll ans=1; while(b) { if(b&1) { ans=ans*a%p; } b>>=1; a=a*a%p; } return ans; } int main() { ll w,n,k; cin>>w>>n>>k; cout<<w*qpow(qpow(2,k,p),p-2,p)%p<<endl; return 0; }
luogu P2184 贪婪大陆
-
询问等价于判断先前加入的地雷区间有多少个与当前询问区间有交,即 \(\sum[x_{l} \le r \land x_{r} \ge l]\) 。
-
用 \(r\) 前面有多少个地雷区间开头和 \(l-1\) 前面有多少个地雷区间结尾相减即可。
点击查看代码
struct BIT { int c[100010]; int lowbit(int x) { return (x&(-x)); } void update(int n,int x,int val) { for(int i=x;i<=n;i+=lowbit(i)) { c[i]+=val; } } int getsum(int x) { int ans=0; for(int i=x;i>=1;i-=lowbit(i)) { ans+=c[i]; } return ans; } }T[2]; int main() { int n,m,pd,l,r,i; cin>>n>>m; for(i=1;i<=m;i++) { cin>>pd>>l>>r; if(pd==1) { T[0].update(n,l,1); T[1].update(n,r,1); } else { cout<<T[0].getsum(r)-T[1].getsum(l-1)<<endl; } } return 0; }
10.23
闲话
- 早读时 \(miaomiao\) 要来了早读资料,说早读是为了让我们换换口味,遂颓《红楼梦》。
- 下午放 @ppllxx_9G 的每日一歌《merry christmas mr lawrence》。
- 下午突然被 \(huge\) 通知下午多校安排了 树上问题 和 动态规划 的讲题,问我们有没有想听的。但我们直到他说才知道今天安排的任务是 动态规划 ,因为昨天改完题就去写板子了,遂以为今天写 树上问题 。然后就被 \(miaomiao\) \(D\) “你们写专题怎么一点也不积极”。
- 吃完晚饭后 \(miaomiao\) 突然神秘兮兮地问我们机房应该没有零食吧?
做题纪要
CF660E Different Subsets For All Tuples
-
考虑计算每个非空子序列单独的贡献。
- 空子序列的贡献为 \(m^{n}\) 。
-
为了去重,只统计每个子序列第一次出现时的贡献。不妨钦定对于同一个颜色段只取最后一个位置的颜色。
-
故 \(m^{n}+\sum\limits_{i=1}^{n}m^{i}\sum\limits_{j=i}^{n}\dbinom{j-1}{i-1}(m-1)^{j-i}m^{n-j}\) 即为所求。
- 枚举 \(j\) 本质上是枚举颜色段然后进行插板。
- 又因为相邻两个颜色段间的元素不能相同,所以要乘以 \((m-1)^{j-i}\) ;而后面的元素又可以随便选了,所以要乘以 \(m^{n-j}\) 。
-
把后面的式子提出来,尝试推导,有 \(\begin{aligned} & \sum\limits_{i=1}^{n}m^{i}\sum\limits_{j=i}^{n}\dbinom{j-1}{i-1}(m-1)^{j-i}m^{n-j} \\ &=\sum\limits_{j=1}^{n}m^{n-j}\sum\limits_{i=1}^{j}\dbinom{j-1}{i-1}(m-1)^{j-i}m^{i} \\ &=\sum\limits_{j=0}^{n-1}m^{n-j-1}\sum\limits_{i=0}^{j}\dbinom{j}{i}(m-1)^{j-i}m^{i+1} \\ &=\sum\limits_{j=0}^{n-1}m^{n-j}\sum\limits_{i=0}^{j}\dbinom{j}{i}(m-1)^{j-i}m^{i} \\ &=\sum\limits_{j=0}^{n-1}m^{n-j}(m-1+m)^{j} \\ &=\sum\limits_{j=0}^{n-1}m^{n-j}(2m-1)^{j} \end{aligned}\) .
点击查看代码
const ll p=1000000007; ll qpow(ll a,ll b,ll p) { ll ans=1; while(b) { if(b&1) { ans=ans*a%p; } b>>=1; a=a*a%p; } return ans; } int main() { ll n,m,ans,i; cin>>n>>m; ans=qpow(m,n,p); for(i=0;i<=n-1;i++) { ans=(ans+qpow(m,n-i,p)*qpow(2*m-1,i,p)%p)%p; } cout<<ans<<endl; return 0; }
CF997E Good Subsegments
-
考虑将询问离线下来进行扫描线,并使用线段树维护历史版本和。
-
因为是排列,所以 \([l,r]\) 是好区间当且仅当 \(\max\limits_{i=l}^{r}\{ a_{i} \}-\min\limits_{i=l}^{r}\{ a_{i} \}=r-l\) ,即 \(\max\limits_{i=l}^{r}\{ a_{i} \}-\min\limits_{i=l}^{r}\{ a_{i} \}-(r-l)=0\) 。
- 对于任意区间均有 \(\max\limits_{i=l}^{r}\{ a_{i} \}-\min\limits_{i=l}^{r}\{ a_{i} \}-(r-l) \ge 0\) 。
-
\(\max,\min\) 自然是要用单调栈维护的。另外考虑维护 \(\max\limits_{i=l}^{r}\{ a_{i} \}-\min\limits_{i=l}^{r}\{ a_{i} \}-(r-l)\) 的最小值及最小值个数,又因为要处理多对区间,故额外维护历史版本最小值即可。
-
注意在下传标记时判断左右儿子最小值是否等于当前区间最小值,等于时才下传标记(因为要进行最小值个数的转移)。
点击查看代码
ll a[120010],ans[120010]; vector<pair<ll,ll> >q[120010]; stack<ll>s1,s2; struct SMT { struct SegmentTree { ll minn,num,hsum,tlazy,lazy; }tree[480010]; ll lson(ll x) { return x*2; } ll rson(ll x) { return x*2+1; } void pushup(ll rt) { tree[rt].minn=min(tree[lson(rt)].minn,tree[rson(rt)].minn); tree[rt].num=(tree[lson(rt)].minn==tree[rt].minn)*tree[lson(rt)].num+(tree[rson(rt)].minn==tree[rt].minn)*tree[rson(rt)].num; tree[rt].hsum=tree[lson(rt)].hsum+tree[rson(rt)].hsum; } void build(ll rt,ll l,ll r) { if(l==r) { tree[rt].minn=0; tree[rt].num=1; return; } ll mid=(l+r)/2; build(lson(rt),l,mid); build(rson(rt),mid+1,r); pushup(rt); } void pushlazy(ll rt,ll lazy,ll tlazy,ll minn) { tree[rt].minn+=lazy; tree[rt].lazy+=lazy; if(tree[rt].minn==minn) { tree[rt].hsum+=tlazy*tree[rt].num; tree[rt].tlazy+=tlazy; } } void pushdown(ll rt) { pushlazy(lson(rt),tree[rt].lazy,tree[rt].tlazy,tree[rt].minn); pushlazy(rson(rt),tree[rt].lazy,tree[rt].tlazy,tree[rt].minn); tree[rt].lazy=tree[rt].tlazy=0; } void update_val(ll rt,ll l,ll r,ll x,ll y,ll val) { if(x<=l&&r<=y) { tree[rt].minn+=val; tree[rt].lazy+=val; return; } pushdown(rt); ll mid=(l+r)/2; if(x<=mid) { update_val(lson(rt),l,mid,x,y,val); } if(y>mid) { update_val(rson(rt),mid+1,r,x,y,val); } pushup(rt); } void update_tim(ll rt,ll l,ll r,ll x,ll y,ll val) { if(x<=l&&r<=y) { if(tree[rt].minn==0) { tree[rt].hsum+=val*tree[rt].num; tree[rt].tlazy+=val; } return; } pushdown(rt); ll mid=(l+r)/2; if(x<=mid) { update_tim(lson(rt),l,mid,x,y,val); } if(y>mid) { update_tim(rson(rt),mid+1,r,x,y,val); } pushup(rt); } ll query(ll rt,ll l,ll r,ll x,ll y) { if(x<=l&&r<=y) { return tree[rt].hsum; } pushdown(rt); 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; } }T; int main() { ll n,m,l,r,tmp,i,j; cin>>n; for(i=1;i<=n;i++) { cin>>a[i]; } cin>>m; for(i=1;i<=m;i++) { cin>>l>>r; q[r].push_back(make_pair(l,i)); } T.build(1,1,n); for(i=1;i<=n;i++) { while(s1.empty()==0&&a[s1.top()]>a[i]) { tmp=s1.top(); s1.pop(); T.update_val(1,1,n,((s1.empty()==0)?s1.top():0)+1,tmp,a[tmp]-a[i]);//最小值由 a[s1.top()] 变成了 a[i] } while(s2.empty()==0&&a[s2.top()]<a[i]) { tmp=s2.top(); s2.pop(); T.update_val(1,1,n,((s2.empty()==0)?s2.top():0)+1,tmp,a[i]-a[tmp]);//最大值由 a[s2.top()] 变成了 a[i] } s1.push(i); s2.push(i); if(i-1>=1) { T.update_val(1,1,n,1,i-1,-1);//右端点 +1 ,左端点不动 } T.update_tim(1,1,n,1,i,1);//统计一次历史和 for(j=0;j<q[i].size();j++) { ans[q[i][j].second]=T.query(1,1,n,q[i][j].first,i); } } for(i=1;i<=m;i++) { cout<<ans[i]<<endl; } return 0; }
CF526F Pudding Monsters
-
因为每行每列恰好有一个棋子,故 \(k \times k\) 的子棋盘中恰好有 \(k\) 个棋子等价于这 \(k\) 个棋子的横坐标最大值减去横坐标最小值等于纵坐标最大值减去纵坐标最小值,且等于 \(k-1\) 。
-
按 \(\{ x \}\) 排序后就和 CF997E Good Subsegments 一样做了。
点击查看代码
ll ans[300010]; pair<ll,ll>a[300010]; vector<pair<ll,ll> >q[300010]; stack<ll>s1,s2; struct SMT { struct SegmentTree { ll minn,num,hsum,tlazy,lazy; }tree[1200010]; ll lson(ll x) { return x*2; } ll rson(ll x) { return x*2+1; } void pushup(ll rt) { tree[rt].minn=min(tree[lson(rt)].minn,tree[rson(rt)].minn); tree[rt].num=(tree[lson(rt)].minn==tree[rt].minn)*tree[lson(rt)].num+(tree[rson(rt)].minn==tree[rt].minn)*tree[rson(rt)].num; tree[rt].hsum=tree[lson(rt)].hsum+tree[rson(rt)].hsum; } void build(ll rt,ll l,ll r) { if(l==r) { tree[rt].minn=0; tree[rt].num=1; return; } ll mid=(l+r)/2; build(lson(rt),l,mid); build(rson(rt),mid+1,r); pushup(rt); } void pushlazy(ll rt,ll lazy,ll tlazy,ll minn) { tree[rt].minn+=lazy; tree[rt].lazy+=lazy; if(tree[rt].minn==minn) { tree[rt].hsum+=tlazy*tree[rt].num; tree[rt].tlazy+=tlazy; } } void pushdown(ll rt) { pushlazy(lson(rt),tree[rt].lazy,tree[rt].tlazy,tree[rt].minn); pushlazy(rson(rt),tree[rt].lazy,tree[rt].tlazy,tree[rt].minn); tree[rt].lazy=tree[rt].tlazy=0; } void update_val(ll rt,ll l,ll r,ll x,ll y,ll val) { if(x<=l&&r<=y) { tree[rt].minn+=val; tree[rt].lazy+=val; return; } pushdown(rt); ll mid=(l+r)/2; if(x<=mid) { update_val(lson(rt),l,mid,x,y,val); } if(y>mid) { update_val(rson(rt),mid+1,r,x,y,val); } pushup(rt); } void update_tim(ll rt,ll l,ll r,ll x,ll y,ll val) { if(x<=l&&r<=y) { if(tree[rt].minn==0) { tree[rt].hsum+=val*tree[rt].num; tree[rt].tlazy+=val; } return; } pushdown(rt); ll mid=(l+r)/2; if(x<=mid) { update_tim(lson(rt),l,mid,x,y,val); } if(y>mid) { update_tim(rson(rt),mid+1,r,x,y,val); } pushup(rt); } ll query(ll rt,ll l,ll r,ll x,ll y) { if(x<=l&&r<=y) { return tree[rt].hsum; } pushdown(rt); 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; } }T; int main() { ll n,m=1,tmp,i,j; cin>>n; for(i=1;i<=n;i++) { cin>>a[i].first>>a[i].second; } sort(a+1,a+1+n); q[n].push_back(make_pair(1,1)); T.build(1,1,n); for(i=1;i<=n;i++) { while(s1.empty()==0&&a[s1.top()].second>a[i].second) { tmp=s1.top(); s1.pop(); T.update_val(1,1,n,((s1.empty()==0)?s1.top():0)+1,tmp,a[tmp].second-a[i].second); } while(s2.empty()==0&&a[s2.top()].second<a[i].second) { tmp=s2.top(); s2.pop(); T.update_val(1,1,n,((s2.empty()==0)?s2.top():0)+1,tmp,a[i].second-a[tmp].second); } s1.push(i); s2.push(i); if(i-1>=1) { T.update_val(1,1,n,1,i-1,-1); } T.update_tim(1,1,n,1,i,1); for(j=0;j<q[i].size();j++) { ans[q[i][j].second]=T.query(1,1,n,q[i][j].first,i); } } for(i=1;i<=m;i++) { cout<<ans[i]<<endl; } return 0; }
SP6779 GSS7 - Can you answer these queries VII
-
树剖直接维护即可。
-
注意在处理询问时两条链分开考虑,注意下由于 \(DFS\) 序产生的合并顺序。
点击查看代码
struct node { ll nxt,to; }e[200010]; ll head[200010],c[200010],cc[200010],fa[200010],siz[200010],dep[200010],son[200010],top[200010],dfn[200010],cnt=0,tot=0; void add(ll u,ll v) { cnt++; e[cnt].nxt=head[u]; e[cnt].to=v; head[u]=cnt; } 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) { tot++; dfn[x]=tot; cc[tot]=c[x]; 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); } } } } struct SegmentTree { ll len,sum,pre,suf,ans,lazy; }tree[400010]; ll lson(ll x) { return x*2; } ll rson(ll x) { return x*2+1; } void pushup(SegmentTree &ans,SegmentTree p,SegmentTree q) { ans.sum=p.sum+q.sum; ans.pre=max(p.pre,p.sum+q.pre); ans.suf=max(q.suf,q.sum+p.suf); ans.ans=max(p.ans,max(q.ans,p.suf+q.pre)); } void build(ll rt,ll l,ll r) { tree[rt].len=r-l+1; tree[rt].lazy=0x7f7f7f7f; if(l==r) { tree[rt].sum=cc[l]; tree[rt].pre=tree[rt].suf=tree[rt].ans=max(0ll,tree[rt].sum); return; } ll mid=(l+r)/2; build(lson(rt),l,mid); build(rson(rt),mid+1,r); pushup(tree[rt],tree[lson(rt)],tree[rson(rt)]); } void pushlazy(ll rt,ll lazy) { tree[rt].sum=lazy*tree[rt].len; tree[rt].pre=tree[rt].suf=tree[rt].ans=max(0ll,tree[rt].sum); tree[rt].lazy=lazy; } void pushdown(ll rt) { if(tree[rt].lazy!=0x7f7f7f7f) { pushlazy(lson(rt),tree[rt].lazy); pushlazy(rson(rt),tree[rt].lazy); tree[rt].lazy=0x7f7f7f7f; } } void update(ll rt,ll l,ll r,ll x,ll y,ll val) { if(x<=l&&r<=y) { pushlazy(rt,val); return; } pushdown(rt); ll mid=(l+r)/2; if(x<=mid) { update(lson(rt),l,mid,x,y,val); } if(y>mid) { update(rson(rt),mid+1,r,x,y,val); } pushup(tree[rt],tree[lson(rt)],tree[rson(rt)]); } SegmentTree query(ll rt,ll l,ll r,ll x,ll y) { if(x<=l&&r<=y) { return tree[rt]; } pushdown(rt); ll mid=(l+r)/2; SegmentTree ans; if(y<=mid) { return query(lson(rt),l,mid,x,y); } else { if(x>mid) { return query(rson(rt),mid+1,r,x,y); } else { pushup(ans,query(lson(rt),l,mid,x,y),query(rson(rt),mid+1,r,x,y)); return ans; } } } void update1(ll u,ll v,ll val,ll n) { while(top[u]!=top[v]) { if(dep[top[u]]>dep[top[v]]) { update(1,1,n,dfn[top[u]],dfn[u],val); u=fa[top[u]]; } else { update(1,1,n,dfn[top[v]],dfn[v],val); v=fa[top[v]]; } } if(dep[u]>dep[v]) { update(1,1,n,dfn[v],dfn[u],val); } else { update(1,1,n,dfn[u],dfn[v],val); } } ll query1(ll u,ll v,ll n) { SegmentTree p=(SegmentTree){0,0,0,0,0,0},q=(SegmentTree){0,0,0,0,0,0}; while(top[u]!=top[v]) { if(dep[top[u]]>dep[top[v]]) { pushup(p,query(1,1,n,dfn[top[u]],dfn[u]),p); u=fa[top[u]]; } else { pushup(q,query(1,1,n,dfn[top[v]],dfn[v]),q); v=fa[top[v]]; } } if(dep[u]>dep[v]) { pushup(p,query(1,1,n,dfn[v],dfn[u]),p); } else { pushup(q,query(1,1,n,dfn[u],dfn[v]),q); } swap(p.suf,p.pre); pushup(p,p,q); return p.ans; } int main() { ll n,m,u,v,w,pd,i; cin>>n; for(i=1;i<=n;i++) { cin>>c[i]; } for(i=1;i<=n-1;i++) { cin>>u>>v; add(u,v); add(v,u); } dfs1(1,0); dfs2(1,1); build(1,1,n); cin>>m; for(i=1;i<=m;i++) { cin>>pd>>u>>v; if(pd==1) { cout<<query1(u,v,n)<<endl; } else { cin>>w; update1(u,v,w,n); } } return 0; }
SP4487 GSS6 - Can you answer these queries VI
-
\(FHQ-Treap\) 按大小分裂维护即可,写法和 luogu P4036 [JSOI2008] 火星人 差不多。
-
注意本题中最大子段和选出的子段不能是空段。
点击查看代码
ll a[200010]; struct BST { ll rt_sum,root; struct FHQ_Treap { ll son[2],val,rnd,cnt,siz,sum,pre,suf,ans; }tree[200010]; #define lson(rt) (tree[rt].son[0]) #define rson(rt) (tree[rt].son[1]) void init() { rt_sum=root=0; tree[0].ans=-0x7f7f7f7f; srand(time(0)); } void pushup(ll rt) { tree[rt].siz=tree[lson(rt)].siz+tree[rson(rt)].siz+tree[rt].cnt; tree[rt].sum=tree[lson(rt)].sum+tree[rt].val+tree[rson(rt)].sum; tree[rt].pre=max(tree[lson(rt)].pre,tree[lson(rt)].sum+tree[rt].val+tree[rson(rt)].pre); tree[rt].suf=max(tree[rson(rt)].suf,tree[lson(rt)].suf+tree[rt].val+tree[rson(rt)].sum); tree[rt].ans=max(tree[lson(rt)].ans,max(tree[rson(rt)].ans,tree[lson(rt)].suf+tree[rt].val+tree[rson(rt)].pre)); } ll build_rt(ll val) { rt_sum++; lson(rt_sum)=rson(rt_sum)=0; tree[rt_sum].sum=tree[rt_sum].ans=tree[rt_sum].val=val; tree[rt_sum].pre=tree[rt_sum].suf=max(val,0ll); tree[rt_sum].rnd=rand(); tree[rt_sum].cnt=tree[rt_sum].siz=1; return rt_sum; } void split(ll rt,ll k,ll &ls,ll &rs) { if(rt==0) { ls=rs=0; return; } if(tree[lson(rt)].siz+tree[rt].cnt<=k) { ls=rt; split(rson(rt),k-tree[lson(rt)].siz-tree[rt].cnt,rson(ls),rs); } else { rs=rt; split(lson(rs),k,ls,lson(rs)); } pushup(rt); } ll merge(ll rt1,ll rt2) { if(rt1==0||rt2==0) { return rt1+rt2; } if(tree[rt1].rnd<tree[rt2].rnd) { rson(rt1)=merge(rson(rt1),rt2); pushup(rt1); return rt1; } else { lson(rt2)=merge(rt1,lson(rt2)); pushup(rt2); return rt2; } } void insert(ll pos,ll val) { ll ls,rs; split(root,pos,ls,rs); root=merge(merge(ls,build_rt(val)),rs); } void del(ll pos) { ll ls,rs,rt; split(root,pos,ls,rs); split(ls,pos-1,ls,rt); root=merge(merge(ls,merge(lson(rt),rson(rt))),rs); } void update(ll pos,ll val) { ll ls,rs,rt; split(root,pos,ls,rs); split(ls,pos-1,ls,rt); tree[rt].val=val; pushup(rt); root=merge(merge(ls,rt),rs); } ll query(ll l,ll r) { ll ls,rs,rt,ans; split(root,r,ls,rs); split(ls,l-1,ls,rt); ans=tree[rt].ans; root=merge(merge(ls,rt),rs); return ans; } }T; int main() { ll n,m,l,r,i; char pd; cin>>n; T.init(); for(i=1;i<=n;i++) { cin>>a[i]; T.insert(i-1,a[i]); } cin>>m; for(i=1;i<=m;i++) { cin>>pd>>l; if(pd=='I') { cin>>r; T.insert(l-1,r); } if(pd=='D') { T.del(l); } if(pd=='R') { cin>>r; T.update(l,r); } if(pd=='Q') { cin>>r; cout<<T.query(l,r)<<endl; } } return 0; }
SP3109 STRLCP - Longest Common Prefix
-
多倍经验: luogu P4036 [JSOI2008] 火星人
点击查看代码
const ull base=13331; ull jc[300010]; char s[300010]; struct BST { const ll INF=0x7f7f7f7f; ll rt_sum,root; struct FHQ_Treap { ll son[2],rnd,cnt,siz; ull val,hsh; }tree[300010]; #define lson(rt) (tree[rt].son[0]) #define rson(rt) (tree[rt].son[1]) void init() { rt_sum=root=0; memset(tree,0,sizeof(tree)); srand(time(0)); } void pushup(ll rt) { tree[rt].siz=tree[lson(rt)].siz+tree[rson(rt)].siz+tree[rt].cnt; tree[rt].hsh=tree[lson(rt)].hsh*jc[tree[rson(rt)].siz+tree[rt].cnt]+tree[rt].val*jc[tree[rson(rt)].siz]+tree[rson(rt)].hsh; } ll build(ll val) { rt_sum++; lson(rt_sum)=rson(rt_sum)=0; tree[rt_sum].rnd=rand(); tree[rt_sum].cnt=tree[rt_sum].siz=1; tree[rt_sum].val=tree[rt_sum].hsh=val; return rt_sum; } void split(ll rt,ll k,ll &ls,ll &rs) { if(rt==0) { ls=rs=0; return; } if(tree[lson(rt)].siz+tree[rt].cnt<=k) { ls=rt; split(rson(ls),k-tree[lson(rt)].siz-tree[rt].cnt,rson(ls),rs); } else { rs=rt; split(lson(rs),k,ls,lson(rs)); } pushup(rt); } ll merge(ll rt1,ll rt2) { if(rt1==0||rt2==0) { return rt1+rt2; } if(tree[rt1].rnd<tree[rt2].rnd) { rson(rt1)=merge(rson(rt1),rt2); pushup(rt1); return rt1; } else { lson(rt2)=merge(rt1,lson(rt2)); pushup(rt2); return rt2; } } void insert(ll pos,ll val) { ll ls,rs; split(root,pos,ls,rs); root=merge(merge(ls,build(val)),rs); } void update(ll pos,ll val) { ll ls,rs,mid; split(root,pos,ls,rs); split(ls,pos-1,ls,mid); tree[mid].val=tree[mid].hsh=val; root=merge(merge(ls,mid),rs); } ull query(ll l,ll r) { ll ls,rs,mid; ull ans; split(root,r,ls,rs); split(ls,l-1,ls,mid); ans=tree[mid].hsh; root=merge(merge(ls,mid),rs); return ans; } }T; bool check(ll mid,ll l,ll r) { return (T.query(l,l+mid-1)==T.query(r,r+mid-1)); } ll query_lcp(ll len,ll x,ll y) { if(x>y) { swap(x,y); } ll l=0,r=len-y+1,mid,ans=0; while(l<=r) { mid=(l+r)/2; if(check(mid,x,y)==true) { ans=mid; l=mid+1; } else { r=mid-1; } } return ans; } int main() { ll t,n,m,x,y,i,j; char pd,d; cin>>t; for(i=0;i<=200000;i++) { jc[i]=(i==0)?1:(jc[i-1]*base); } for(j=1;j<=t;j++) { cin>>(s+1)>>m; n=strlen(s+1); T.init(); for(i=1;i<=n;i++) { T.insert(i-1,s[i]); } for(i=1;i<=m;i++) { cin>>pd; if(pd=='Q') { cin>>x>>y; cout<<query_lcp(n,x,y)<<endl; } if(pd=='R') { cin>>x>>d; T.update(x,d); } if(pd=='I') { cin>>x>>d; n++; T.insert(x,d); } } } return 0; }
CF825G Tree Queries
LibreOJ 137. 最小瓶颈路(加强版)
-
\(Kruskal\) 重构树板子。
点击查看代码
const int p=1000000007; struct node { int from,to,w; }E[100010]; int A,B,C,P,dep[70010],siz[70010],fa[70010],son[70010],top[70010],dfn[70010],c[70010],cc[70010],tot=0; vector<node>tmp; vector<int>e[70010]; bool cmp(node a,node b) { return a.w<b.w; } void add(int u,int v) { e[u].push_back(v); } struct DSU { int fa[70010]; void init(int n) { for(int i=1;i<=n;i++) { fa[i]=i; } } int find(int x) { return fa[x]==x?x:fa[x]=find(fa[x]); } }D; void kruskal(int n,int m) { sort(E+1,E+1+m,cmp); D.init(n); for(int i=1;i<=m;i++) { int x=D.find(E[i].from),y=D.find(E[i].to); if(x!=y) { D.fa[x]=y; tmp.push_back((node){E[i].from,E[i].to,E[i].w}); add(E[i].from,E[i].to); add(E[i].to,E[i].from); } } } void dfs1(int x,int father) { siz[x]=1; fa[x]=father; dep[x]=dep[father]+1; for(int i=0;i<e[x].size();i++) { if(e[x][i]!=father) { dfs1(e[x][i],x); siz[x]+=siz[e[x][i]]; son[x]=(siz[e[x][i]]>siz[son[x]])?e[x][i]:son[x]; } } } void dfs2(int x,int id) { tot++; dfn[x]=tot; cc[tot]=c[x]; top[x]=id; if(son[x]!=0) { dfs2(son[x],id); for(int i=0;i<e[x].size();i++) { if(e[x][i]!=fa[x]&&e[x][i]!=son[x]) { dfs2(e[x][i],e[x][i]); } } } } struct ST { int fmaxx[70010][20]; void init(int n) { for(int i=1;i<=n;i++) { fmaxx[i][0]=cc[i]; } for(int j=1;j<=log2(n);j++) { for(int i=1;i+(1<<j)-1<=n;i++) { fmaxx[i][j]=max(fmaxx[i][j-1],fmaxx[i+(1<<(j-1))][j-1]); } } } int query(int l,int r) { int t=log2(r-l+1); return max(fmaxx[l][t],fmaxx[r-(1<<t)+1][t]); } }S; int query1(int u,int v) { int ans=0; while(top[u]!=top[v]) { if(dep[top[u]]>dep[top[v]]) { ans=max(ans,S.query(dfn[top[u]],dfn[u])); u=fa[top[u]]; } else { ans=max(ans,S.query(dfn[top[v]],dfn[v])); v=fa[top[v]]; } } if(u!=v) { if(dep[u]>dep[v]) { ans=max(ans,S.query(dfn[v]+1,dfn[u])); } else { ans=max(ans,S.query(dfn[u]+1,dfn[v])); } } return ans; } int rnd() { return A=(A*B+C)%P; } int main() { int n,m,q,u,v,ans=0,i; scanf("%d%d",&n,&m); for(i=1;i<=m;i++) { scanf("%d%d%d",&E[i].from,&E[i].to,&E[i].w); } kruskal(n,m); dfs1(1,0); for(i=0;i<tmp.size();i++) { if(dep[tmp[i].from]>dep[tmp[i].to]) { c[tmp[i].from]=tmp[i].w; } else { c[tmp[i].to]=tmp[i].w; } } dfs2(1,1); S.init(n); scanf("%d%d%d%d%d",&q,&A,&B,&C,&P); for(i=1;i<=q;i++) { u=rnd()%n+1; v=rnd()%n+1; ans=(ans+query1(u,v)%p)%p; } printf("%d\n",ans); return 0; }
LibreOJ 139. 树链剖分
-
树剖板子。
点击查看代码
struct node { ll nxt,to; }e[200010]; ll head[200010],siz[200010],dep[200010],fa[200010],son[200010],top[200010],c[200010],cc[200010],dfn[200010],out[200010],cnt=0,tot=0; void add(ll u,ll v) { cnt++; e[cnt].nxt=head[u]; e[cnt].to=v; head[u]=cnt; } void dfs1(ll x) { siz[x]=1; dep[x]=dep[fa[x]]+1; for(ll i=head[x];i!=0;i=e[i].nxt) { dfs1(e[i].to); 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; tot++; dfn[x]=tot; cc[tot]=c[x]; if(son[x]!=0) { dfs2(son[x],id); for(ll i=head[x];i!=0;i=e[i].nxt) { if(e[i].to!=son[x]) { dfs2(e[i].to,e[i].to); } } } out[x]=tot; } struct SMT { struct SegmentTree { ll len,sum,lazy; }tree[800010]; ll lson(ll x) { return x*2; } ll rson(ll x) { return x*2+1; } void pushup(ll rt) { tree[rt].sum=tree[lson(rt)].sum+tree[rson(rt)].sum; } void build(ll rt,ll l,ll r) { tree[rt].len=r-l+1; if(l==r) { tree[rt].sum=cc[l]; return; } ll mid=(l+r)/2; build(lson(rt),l,mid); build(rson(rt),mid+1,r); pushup(rt); } void pushdown(ll rt) { if(tree[rt].lazy!=0) { tree[lson(rt)].sum+=tree[rt].lazy*tree[lson(rt)].len; tree[rson(rt)].sum+=tree[rt].lazy*tree[rson(rt)].len; tree[lson(rt)].lazy+=tree[rt].lazy; tree[rson(rt)].lazy+=tree[rt].lazy; tree[rt].lazy=0; } } void update(ll rt,ll l,ll r,ll x,ll y,ll val) { if(x<=l&&r<=y) { tree[rt].sum+=val*tree[rt].len; tree[rt].lazy+=val; return; } pushdown(rt); ll mid=(l+r)/2; if(x<=mid) { update(lson(rt),l,mid,x,y,val); } if(y>mid) { update(rson(rt),mid+1,r,x,y,val); } pushup(rt); } ll query(ll rt,ll l,ll r,ll x,ll y) { if(x<=l&&r<=y) { return tree[rt].sum; } pushdown(rt); 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; } }T; ll dirson(ll u,ll v) { if(dep[u]>dep[v]) { swap(u,v); } while(top[u]!=top[v]) { if(dep[top[u]]>dep[top[v]]) { if(fa[top[u]]==v) { return top[u]; } u=fa[top[u]]; } else { if(fa[top[v]]==u) { return top[v]; } v=fa[top[v]]; } } return (dep[u]<dep[v])?son[u]:son[v]; } void update1(ll u,ll v,ll val,ll n) { while(top[u]!=top[v]) { if(dep[top[u]]>dep[top[v]]) { T.update(1,1,n,dfn[top[u]],dfn[u],val); u=fa[top[u]]; } else { T.update(1,1,n,dfn[top[v]],dfn[v],val); v=fa[top[v]]; } } if(dep[u]>dep[v]) { T.update(1,1,n,dfn[v],dfn[u],val); } else { T.update(1,1,n,dfn[u],dfn[v],val); } } void update2(ll u,ll val,ll n) { T.update(1,1,n,dfn[u],out[u],val); } void update3(ll u,ll rt,ll val,ll n) { if(u==rt) { update2(1,val,n); } else { if(dfn[u]<=dfn[rt]&&dfn[rt]<=out[u]) { update2(1,val,n); update2(dirson(u,rt),-val,n); } else { update2(u,val,n); } } } ll query1(ll u,ll v,ll n) { ll ans=0; while(top[u]!=top[v]) { if(dep[top[u]]>dep[top[v]]) { ans+=T.query(1,1,n,dfn[top[u]],dfn[u]); u=fa[top[u]]; } else { ans+=T.query(1,1,n,dfn[top[v]],dfn[v]); v=fa[top[v]]; } } if(dep[u]>dep[v]) { ans+=T.query(1,1,n,dfn[v],dfn[u]); } else { ans+=T.query(1,1,n,dfn[u],dfn[v]); } return ans; } ll query2(ll u,ll n) { return T.query(1,1,n,dfn[u],out[u]); } ll query3(ll u,ll rt,ll n) { if(u==rt) { return query2(1,n); } else { if(dfn[u]<=dfn[rt]&&dfn[rt]<=out[u]) { return query2(1,n)-query2(dirson(u,rt),n); } else { return query2(u,n); } } } int main() { ll n,m,pd,u,v,w,rt=1,i; scanf("%lld",&n); for(i=1;i<=n;i++) { scanf("%lld",&c[i]); } for(i=2;i<=n;i++) { scanf("%lld",&fa[i]); add(fa[i],i); } dfs1(1); dfs2(1,1); T.build(1,1,n); scanf("%lld",&m); for(i=1;i<=m;i++) { scanf("%lld%lld",&pd,&u); if(pd==1) { rt=u; } if(pd==2) { scanf("%lld%lld",&v,&w); update1(u,v,w,n); } if(pd==3) { scanf("%lld",&w); update3(u,rt,w,n); } if(pd==4) { scanf("%lld",&v); printf("%lld\n",query1(u,v,n)); } if(pd==5) { printf("%lld\n",query3(u,rt,n)); } } return 0; }
luogu P8779 [蓝桥杯 2022 省 A] 推导部分和
-
差分约束板子。
点击查看代码
struct node { ll nxt,to,w; }e[400010]; ll head[400010],vis[400010],dis[400010],col[400010],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; } void spfa(ll s,ll id) { queue<ll>q; q.push(s); dis[s]=0; vis[s]=1; while(q.empty()==0) { ll x=q.front(); col[x]=id; vis[x]=0; q.pop(); for(ll i=head[x];i!=0;i=e[i].nxt) { if(dis[e[i].to]>dis[x]+e[i].w) { dis[e[i].to]=dis[x]+e[i].w; if(vis[e[i].to]==0) { q.push(e[i].to); vis[e[i].to]=1; } } } } } int main() { ll n,m,q,l,r,s,i; cin>>n>>m>>q; for(i=1;i<=n;i++) { add(n+1,i,0); } for(i=1;i<=m;i++) { cin>>l>>r>>s; add(r,l-1,-s); add(l-1,r,s); } memset(vis,0,sizeof(vis)); memset(dis,0x3f,sizeof(dis)); for(i=0;i<=n;i++) { if(col[i]==0) { spfa(i,i+1); } } for(i=1;i<=q;i++) { cin>>l>>r; if(col[l-1]!=col[r]) { cout<<"UNKNOWN"<<endl; } else { cout<<dis[r]-dis[l-1]<<endl; } } return 0; }
[ABC238E] Range Sums
-
并查集板子。
点击查看代码
struct DSU { ll fa[200010],l[200010]; void init(int n) { for(ll i=0;i<=n;i++) { fa[i]=i; } } ll find(ll x) { return fa[x]==x?x:fa[x]=find(fa[x]); } void merge(ll x,ll y) { x=find(x); y=find(y); if(x!=y) { fa[x]=y; } } }D; int main() { ll n,m,l,r,i; cin>>n>>m; D.init(n); for(i=1;i<=m;i++) { cin>>l>>r; D.merge(l-1,r); } if(D.find(0)==D.find(n)) { cout<<"Yes"<<endl; } else { cout<<"No"<<endl; } return 0; }
10.24
闲话
- 因为是考前在学校的最后一天,所以 \(field\) 让早读时好好打打板子,遂没上英语早读。临结束时说让我们尽量在 \(7:30\) 前就把厕所上好,别等模拟赛刚开始就去上厕所。
- 上午 \(7:30 \sim 11:36\) 打 accoders NOI 的模拟赛。临开始时才通知我们要打乱座位后再打模拟赛,然后就花了 \(7 \min\) 左右现场使用 \(xlsx\) 出随机数排序加手动指定座位;临结束时 \(feifei\) 让我们上 NOI 官网看下自己准考证,并按照正常流程命名。
- 详见 2024 CSP-S 游记 10.24 。
- 下午放 @lhx 的每日一歌《给我一首歌的时间》,然后听多校的讲题。
做题纪要
TG403. Alice 和璀璨花
TG404. Bob 与幸运日
TG406. David 与和谐号
10.25
闲话
- 详见 2024 CSP-S 游记 10.25 。
做题纪要
10.26
闲话
- 详见 2024 CSP-S 游记 10.26 。
做题纪要
luogu P11231 [CSP-S 2024] 决斗
luogu P11232 [CSP-S 2024] 超速检测
10.27
闲话
- 详见 2024 CSP-S 游记 10.27 。
做题纪要
10.28
闲话
- 详见 2024 CSP-S 游记 10.28 。
- 中午 \(miaomiao\) 说今天估计是补不了 \(whk\) 了,等明天再开始补 \(whk\) ; \(huge\) 来转悠时问我们能不能把机房里的书都搬到教室,然后我们说 \(miaomiao\) 让我们补 \(whk\) 需要用到,接着 \(huge\) 才意识到 \(miaomiao\) 让我们补 \(whk\) ,貌似教练之间消息又不互通了。
- 下午 \(huge\) 不知道找 \(miaomiao\) 过来说什么事情。说完后 \(huge\) 就站在教师机旁边站着看手机,过了一会儿 \(miaomiao\) 说“回去吧,还在这里待着干啥”,语气与当时和 @Vsinger_洛天依 说的语气一样。
- 临吃晚饭时 \(miaomiao\) 让我们把机房收拾了下,准备明天开始补 \(whk\) 。还 \(D\) 了下 @5k_sync_closer , @int_R , @Estelle_N 等人他一开门就回头看一眼,还看
微博博客、翻讨论,说他可能要把 luogu 禁掉。 - \(miaomiao\) 又把机房的铃声换成了类似敲钟的铃声,这次 \(feifei\) 没管。
- 晚上 \(huge\) 来后让我们商讨了下补课的意见,貌似是统一用投屏放课,而具体放什么科目由我们决定。
做题纪要
luogu P11233 [CSP-S 2024] 染色
- 多倍经验:CF1799D1 Hot Start Up (easy version) | CF1799D2 Hot Start Up (hard version)
- 详见 2024 CSP-S 第二轮 T2 luogu P11233 [CSP-S 2024] 染色 。
10.29
闲话
- 补 \(whk\) 。
做题纪要
10.30
闲话
- 补 \(whk\) 。
- 晚饭时突然被 \(feifei\) 通知吃饭时间改了。晚饭时间我们是 \(18:25\) ,高二那边是 \(18:20\) ;早饭我们是 \(7:13\) ,高二那边是 \(7:00\) ;午饭时间忘了。他觉得早午吃饭时间不太合理,让我们有意见可以去找 \(miaomiao\) 协调,他啥事不管。然后说今天晚上让我们先跟着高二的一起去吃饭,以后的时间我们再去找 \(miaomiao\) 协调。
做题纪要
SP7739 BOI7SOU - Sound
10.31
闲话
- 候操时得知中午 \(12:05\) 吃饭,晚上 \(18:15\) 吃饭,这也和昨天 \(feifei\) 跟我们说的时候不一样啊。
- 补 \(whk\) 。补完了物理、化学、生物。
做题纪要
本文来自博客园,作者:hzoi_Shadow,原文链接:https://www.cnblogs.com/The-Shadow-Dragon/p/18487944,未经允许严禁转载。
版权声明:本作品采用 「署名-非商业性使用-相同方式共享 4.0 国际」许可协议(CC BY-NC-SA 4.0) 进行许可。