SSP Round 题解

· · 题解

前言

T1 数据造水了。谢罪。

T3 数据造水且造错了,最后修了三次才对。谢罪谢罪谢罪。

题目难度可能偏高,这是赛前没有预料到的,比较抱歉。

U606783 缥缈愿

出处:SDSC2025 D1T1 By yixiuge777.

该题在原赛时作为 T1 通过率为 \frac {15}{48}

Sol.5,6 是两种不同的 std。

题意

给出长为 n 的序列 a_i,可进行一次区间加 k 操作,求全局 GCD 的最大值。多测,T\le 3,n\le6\times10^5,a_i,k\le 10^{18}

Sol.1

暴力枚举 [l,r] 后暴力计算 GCD。时间复杂度 O(n^3\log V),期望得分 10

Sol.2

预处理前后缀 GCD,然后先枚举 l,在枚举 r 的过程中维护中间部分 a_i+k 的 GCD。时间复杂度 O(n^2\log V),期望得分 30

Sol.3

答案较小时可枚举答案 res,若存在 res\nmid a_ires\nmid a_i+k,则该答案一定不合法。之后每个 a_i 可能必须加 k,可能必须不加,也可能两者皆可。找到必须加的第一个和最后一个位置 [l,r],当且仅当该区间内部都能加时答案合法。时间复杂度 O(nV_r),其中 V_r 为答案值域。期望得分 20

Sol.4

a_1=1 时,若 l>1 则 GCD 必为 1,因此 l=1。类似 Sol.2 中的方式枚举 r 即可,a_n=1 的情况是类似的。时间复杂度 O(n\log V),加上 Sol.2 期望得分 40,拼上 Sol.3 期望得分 60

Sol.5,6

观察一下答案结构,是前后缀各一段再拼上中间加 k 的形式。又由于前缀 GCD 只有 O(\log V) 段不同取值,猜想每段有用的 l 很少。事实的确如此,若结尾在 [L,R] 内的前缀 GCD 均为 g,则 l=R+1l\in [L+1,R+1] 中一定最优。证明考虑最终答案是 g_L,g_M,g_R 三者的 GCD,而这段 l 对应的 g_L 均为 g,此时把尽可能少的数划到中间一定更优。同理也只有 O(\log V) 个有用的 r

Sol.5

可以直接类似 Sol.2 枚举所有有用的 l,同时只在有用的 r 处统计答案。这里由于 GCD 不变时函数只会运行 O(1) 次,直接维护中间部分 GCD 就是 O(n+\log V) 的。由于统计答案时还要算一次 GCD,总复杂度为 O(n\log V+\log ^3V),期望得分 100

Sol.6

直接暴力枚举所有合法对 [l,r]g_Lg_R 容易前后缀预处理。考虑使用 ST 表维护区间 GCD,复杂度 O(n\log^2V+\log^3 V),期望得分 65,拼上 Sol.4 期望得分 75。但 chb 说这个是均摊 O(n\log V) 的,不懂,反正过不了。

事实上注意到关键点只有 O(\log V) 个,考虑只对这些点建 ST 表,即 w_i 表示两个关键点之间的 GCD。预处理 w_i 只需 O(n\log V) 的复杂度,对 w 建出 ST 表后枚举区间即可,总复杂度 O(n\log V+\log^3V),期望得分 100

U606784 虚构义

出处:SDSC2025 D4T2 By Mikefeng.

该题在原赛时作为 T2 通过率为 \frac 7{48}

Sol.6,7,8 是三种不同的 std,均使用 Prim 求解最小生成树,事实上也并没有卡 O(qh^2\log h) 的 Kruskal。

Sol.9 是 chb 提出的做法,作为补充 std。

题意

### Sol.1 暴力对 $O(n)$ 条边跑 Kruskal,时间复杂度 $O(qn\log n)$,期望得分 [$15$](https://www.luogu.com.cn/record/234671085)。 ### Sol.2 $h=2$ 时求 $w$ 的区间最小值,用 ST 表维护即可,时间复杂度 $O(n\log n+q)$,期望得分 [$10$](https://www.luogu.com.cn/record/234671545)。 ### Sol.3 由于点数很少,考虑将 Sol.1 中的 Kruskal 改为 Prim。发现一共只有 $\frac{h(h-1)}2\le 45$ 种边,每种边只会用到 $w$ 最小的一条,因此对每种边求出 $w$ 最小值后跑 Prim 即可,下面 Sol.6,7,8, 的最后一步也是如此。时间复杂度 $O(qn+qh^2)$,期望得分 [$30$](https://www.luogu.com.cn/record/234672634)。 ### Sol.4 对于 $w\le 3$ 的情况,可对每种边再按 $w$ 分类,记录每种 $w$ 的每种边在 $n$ 条边中的位置。之后从小到大枚举 $w$,并试图用这种权值的边更新连通情况,该过程类似 Sol.1。当然也可以用这种方式快速求出每种边的最小值,再跑 Sol.3 中的 Prim。时间复杂度 $O(Vh^2q\log n)$,期望得分 [$10$](https://www.luogu.com.cn/record/234674456)。 ### Sol.5 直接暴力上线段树,每个节点上记录该区间内最小生成森林的所有边,至多 $h$ 条,合并时用 $2h$ 条边跑最小生成树即可。时间复杂度 $O(n\log nh\alpha(h))$,期望得分不知道,由于常数较大,只能过 [$65$](https://www.luogu.com.cn/record/234725993)。 ### Sol.6 对 Sol.3 中的取最小值部分用 ST 表进行优化。然而直接维护 $h^2$ 个 ST 表需要 $O(h^2n\log n)$ 的空间,大概只能接受 $n\le 10^5$。因此改为对每个询问维护 $h^2$ 种边的最大值,然后枚举每种边,建出 ST 表后对所有询问更新,空间复杂度优化到 $O(qh^2+n\log n)$。这两种的时间复杂度均为 $O(h^2n\log n+qh^2)$,前者空间[爆了](https://www.luogu.com.cn/record/234679060),后者期望得分 [$100$](https://www.luogu.com.cn/record/234677036)。 ### Sol.7 Sol.5 中的 $h^2$ 个 ST 表内其实总共只有 $n$ 个元素,因此可以只建大小为 $cnt$ 的 ST 表,查询前映射过去。由于总元素个数有保证,建 ST 表的总时空复杂度为 $O(n\log n)$。比较暴力的映射方式是记录出现的位置,从而二分出左右端点,时间复杂度 $O(qh^2\log n)$,期望得分 [$[65,85]$](https://www.luogu.com.cn/record/234679995)。 考虑去掉二分,直接对每种边开两个长为 $n$ 的数组,记录每个位置左边第一条和右边第一条该种边的编号即可,空间复杂度 $O(h^2n+n\log n)$,时间复杂度 $O(n\log n+h^2n+qh^2)$,期望得分 [$100$](https://www.luogu.com.cn/record/234681078)。 ### Sol.8 是另一种优化 Sol.3 的方式。考虑直接对边的编号 $[1,n]$ 分治,每次处理所有跨过中点 $mid$ 的所有询问,再把其余询问递归下去处理。具体地,每种边在 $[l,mid]$ 内处理一个后缀最小值,$[mid+1,r]$ 内处理一个前缀最小值,询问时把前后缀拼起来即可得到每种边的最小权值。空间复杂度 $O(h^2n)$,时间复杂度 $O(h^2n\log n+qh^2)$,期望得分 [$100$](https://www.luogu.com.cn/record/234685213)。由于~~数据比较水~~常数小,该做法跑得最快。 ### Sol.9 是 chb 的做法。将 Sol.8 的分治与 Sol.5 的维护方式结合起来,每次预处理前后缀最小生成树内的边。这时每次只会加一条边,因此不需要重跑 Kruskal,只需要在原树中 DFS 求路径最大值,并试图用新边替代最大边即可,复杂度 $O(h)$。询问时将前后缀 Kruskal 拼起来得到答案。时间复杂度 $O(hn\log n+qh\alpha(h))$,期望得分 [$100$](https://www.luogu.com.cn/record/234790299)。值得一提的是本题的 $\log n>h$,因此本做法算复杂度可能没有 Sol.7 优。 事实上 Sol.8,9 的分治均可以在线,即猫树分治,先把整个分治结构的信息全存下来,再依次处理每个询问。然而空间复杂度会因此变大不少,可能要乘个 $O(\log n)$,这样 Sol.8 空间就炸了。 ## U606785 短恨歌 出处:可能是原创 By KSCD_. 是从 【数据删除】 的唐氏做法拓展出来的,感觉可能有更优美的做法,欢迎爆标。 【数据删除】 ## U606786 花草野 出处:SDSC2025 D4T4 By Anonyme. 该题在原赛时作为 T4 通过率为 $\frac 1{48}$,非 AC 最高分为 $20$。 这题在原比赛和本比赛应该都是防 AK 题,但在难写的同时兼具一定的学习价值,感觉会了本题就足够精通单侧递归线段树了,故将其搬来作为 T4。另外建议在学习本题之前做做 [P4198](https://www.luogu.com.cn/problem/P4198),并将代码优化得简洁一些,写本题会好写点。 ### 题意 维护一个环,每个点的贡献为经过的 $a$ 最大值乘 $a_i$,需要支持区间覆盖,区间修改,查询给出 $i,z$,询问从 $i$ 开始走到第一个贡献大于 $z$ 的点。$n,q\le 2\times 10^5$。 ### Sol.1 考虑所有 $a_i$ 相等的情况,此时每个区域贡献均为 $a_i^2$,因此答案为 $(i+\lfloor\frac x{a_i^2}\rfloor)\bmod n$,期望得分 [$10$](https://www.luogu.com.cn/record/234711158)。 ### Sol.2 在 $n,q$ 较小时可暴力修改和判断。具体地,先暴力算第一圈能走到哪,若能走完再计算一下 $(\max a_i)(\sum a_i)$,并将剩余的 $x$ 对其取模,即先走完整的若干圈。最后再暴力找最后一圈能走到哪,时间复杂度为 $O(nq)$,拼上 Sol.1 期望得分 [$30$](https://www.luogu.com.cn/record/234711494)。 ### Sol.3 下文中所有 $p$ 均与题面中相同,表示前面走过的最大值。 考虑使用数据结构维护每个区域的贡献,再在该数据结构上二分。由于某个区域的贡献会受到前面最大值的影响,考虑使用单侧递归线段树。在每个节点上维护区间长度 $l$,$a_i$ 的最大值 $x$ 以及只经过该区间的总贡献 $w=\sum a_ip_i$,区间修改为 $k$ 时有 $x=k,w=lk^2$。 然而区间加只维护这些是不够的,区间加 $k$ 时对 $w$ 拆开 $\sum(p_i+k)(a_i+k)$ 得到 $\sum p_ia_i+kp_i+ka_i+k^2$,因此需要维护 $s=\sum a_i,d=\sum p_i$,即有 $w'=w+kd+ks+lk^2$。$s,d$ 修改为 $k$ 时均会变成 $lk$,区间加时均会增加 $lk$,就实现了所有的区间修改。 因此可以类似普通线段树用两个懒标记维护,注意覆盖标记会清空加标记,区间加时若有覆盖标记则加给覆盖标记,懒标记的下传也是容易的。现在需要实现的是 pushup 合并两个区间的操作,这种贡献与前面值有关的合并需要单侧递归。 具体地,设 $lc,rc$ 为线段树上左右儿子,现需合并 $L=lc_u,R=rc_u$ 的信息到 $u$。显然 $L$ 的信息均不变,而 $R$ 的信息可能会受到 $x_L$ 的影响。考虑再将 $R$ 分成 $lc_R$ 和 $rc_{R}$ 两部分,若 $x_{L}\ge x_{lc_R}$,则 $lc_{R}$ 内均以 $x_{L}$ 为 $p$,容易计算,因此记录 $x_L$ 并递归到 $rc_{R}$ 计算贡献;否则 $x_L<x_{lc_R}$,$x_L$ 一定无法越过 $lc_R$,$rc_R$ 的贡献为其在 $R$ 节点内的贡献,可用 $w_R-w_{lc_R}$ 计算,因此记录 $x_L$ 并递归到 $lc_R$ 计算贡献。 每次只会向左右子树中的一个递归,因此单次 pushup 的复杂度是 $O(\log n)$ 的。实现上只需要写成函数,对某节点传入一个前面经过的最大值 $p$,返回其内部考虑上前面的 $p$ 时的信息。上面其实就是调用 $(R,x_L)$ 的过程,具体可能要对 $d,w$ 分别写函数。 这样就以单次修改 $O(\log^2n)$ 的复杂度维护出了任意区间的信息。询问时考虑在线段树上二分,先求出能走到第一圈的哪个位置,过程中还是要带着前面的最大值,需要将该值传到函数里 $O(\log n)$ 确定当前节点的贡献。后面部分需求出最后一圈走到哪个位置,这里只对 $s$ 二分即可。实现起来细节比较多,还要考虑跨过环的情况,具体看代码。时间复杂度 $O(q\log ^2n)$,期望得分 [$100$](https://www.luogu.com.cn/record/234313725)。事实上有一份把二分写在外面的 $O(q\log ^3n)$ 代码也是[可以通过](https://www.luogu.com.cn/record/234313893)的。 ## 后记 [MOCKER44.](https://music.163.com/#/artist?id=32851886) 好听。SSP 是其外号 烧诗P 的缩写,并非费用流算法。 题解修改了三次,谢罪。 下面是各 std 代码: ### U606783 缥缈愿 #### Sol.5 ```cpp #include<iostream> #define ll long long using namespace std; const int N=6e5+10; ll read() { ll s=0,w=1; char ch=getchar(); while(ch<'0'||ch>'9') {if(ch==-1) w=-1; ch=getchar();} while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar(); return s*w; } void print(ll x) { if(x<0) putchar('-'); if(x>=10) print(x/10); putchar(x%10+'0'); } int n,m; ll res,X,a[N],b[N],c[N]; ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;} void sol() { n=read(),X=read(),m=b[0]=c[n+1]=0; for(int i=1;i<=n;i++) a[i]=read(); for(int i=1;i<=n;i++) b[i]=gcd(b[i-1],a[i]); for(int i=n;i>=1;i--) c[i]=gcd(c[i+1],a[i]); res=b[n]; for(int l=1;l<=n;l++) if(b[l]!=b[l-1]) { ll tr=b[l-1]; for(int r=l;r<=n;r++) { tr=gcd(tr,a[r]+X); if(c[r]!=c[r+1]) res=max(res,gcd(tr,c[r+1])); } } print(res),putchar('\n'); } int main() { int TT=read(); while(TT--) sol(); return 0; } ``` #### Sol.6 ```cpp #include<iostream> #define ll long long using namespace std; const int N=6e5+10; const int P=6e5; const int K=19+6; ll read() { ll s=0,w=1; char ch=getchar(); while(ch<'0'||ch>'9') {if(ch==-1) w=-1; ch=getchar();} while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar(); return s*w; } void print(ll x) { if(x<0) putchar('-'); if(x>=10) print(x/10); putchar(x%10+'0'); } int n,m,p[N],lg[N],po[K]; ll res,X,a[N],b[N],c[N],f[K][N]; ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;} ll gcdlr(int l,int r) { if(l>r) return 0; int k=lg[r-l+1]; return gcd(f[k][l],f[k][r-po[k]+1]); } void sol() { n=read(),X=read(),m=b[0]=c[n+1]=0; for(int i=1;i<=n;i++) a[i]=read(); for(int i=1;i<=n;i++) b[i]=gcd(b[i-1],a[i]); for(int i=n;i>=1;i--) c[i]=gcd(c[i+1],a[i]); res=b[n]; for(int i=1;i<=n;i++) if(b[i]!=b[i-1]||c[i]!=c[i-1]) p[++m]=i; p[++m]=n+1; for(int i=1;i<m;i++) { f[0][i]=0; for(int j=p[i];j<p[i+1];j++) f[0][i]=gcd(f[0][i],a[j]+X); } for(int k=1;k<=20;k++) for(int i=1;i+po[k]-1<=m;i++) f[k][i]=gcd(f[k-1][i],f[k-1][i+po[k-1]]); for(int i=1;i<=m;i++) for(int j=i+1;j<=m;j++) res=max(res,gcd(gcdlr(i,j-1),gcd(b[p[i]-1],c[p[j]]))); print(res),putchar('\n'); } int main() { int TT=read(); lg[0]=-1,po[0]=1; for(int i=1;i<=P;i++) lg[i]=lg[i>>1]+1; for(int i=1;i<=20;i++) po[i]=(po[i-1]<<1); while(TT--) sol(); return 0; } ``` ### U606784 虚构义 #### Sol.6 ```cpp #include<iostream> #define ll long long using namespace std; const int N=5e5+10; const int M=45+5; const int inf=1e9+1e7; int h,n,q,ct,id[M][M],d[M][M],ti[N],tw[N],w[N][M],td[M],po[M],lg[N],tl[N],tr[N]; bool vis[N]; struct STtable { int s[M][N]; void build() { for(int k=1;po[k]<=n;k++) for(int i=1;i+po[k]-1<=n;i++) s[k][i]=min(s[k-1][i],s[k-1][i+po[k-1]]); } int query(int l,int r) { int k=lg[r-l+1]; return min(s[k][l],s[k][r-po[k]+1]); } }T; int main() { ios::sync_with_stdio(false),cin.tie(0),cout.tie(0); cin>>h>>n>>q,po[0]=1,lg[0]=-1; for(int i=1;i<=n;i++) lg[i]=lg[i>>1]+1; for(int i=1;i<=20;i++) po[i]=(po[i-1]<<1); for(int i=1;i<=h;i++) for(int j=i+1;j<=h;j++) id[i][j]=++ct; for(int i=1;i<=n;i++) { int u,v; cin>>u>>v>>tw[i]; ti[i]=id[min(u,v)][max(u,v)]; } for(int i=1;i<=q;i++) cin>>tl[i]>>tr[i]; for(int x=1;x<=ct;x++) { for(int i=1;i<=n;i++) T.s[0][i]=(ti[i]==x?tw[i]:inf); T.build(); for(int i=1;i<=q;i++) w[i][x]=T.query(tl[i],tr[i]); } for(int i=1;i<=q;i++) { ll res=0; for(int u=1;u<=h;u++) for(int v=u+1;v<=h;v++) d[u][v]=d[v][u]=w[i][id[u][v]]; for(int i=0;i<=h;i++) td[i]=inf,vis[i]=0; td[1]=0; for(int _=1;_<=h;_++) { int x=0; for(int i=1;i<=h;i++) if(!vis[i]&&td[i]<td[x]) x=i; if(!x) {res=-1; break;} res+=td[x],vis[x]=1; for(int i=1;i<=h;i++) if(!vis[i]) td[i]=min(td[i],d[x][i]); } cout<<res<<'\n'; } return 0; } ``` #### Sol.7 ```cpp #include<iostream> #include<vector> #define pb push_back #define ll long long using namespace std; const int N=5e5+10; const int M=45+5; const int inf=1e9+1e7; int h,n,q,ct,id[M][M],d[M][M],td[M]; int po[M],lg[N],tl[M][N],tr[M][N]; bool vis[M]; vector <int> a[M]; struct STtable { vector <int> st[M]; void build(int id,int n) { for(int i=0;po[i]<=n;i++) st[i].resize(n+2-po[i]); for(int i=1;i<=n;i++) st[0][i]=a[id][i-1]; for(int k=1;po[k]<=n;k++) for(int i=1;i+po[k]-1<=n;i++) st[k][i]=min(st[k-1][i],st[k-1][i+po[k-1]]); } int query(int l,int r) { int k=lg[r-l+1]; return min(st[k][l],st[k][r-po[k]+1]); } }T[M]; int main() { ios::sync_with_stdio(false),cin.tie(0),cout.tie(0); cin>>h>>n>>q,po[0]=1,lg[0]=-1; for(int i=1;i<=n;i++) lg[i]=lg[i>>1]+1; for(int i=1;i<=20;i++) po[i]=(po[i-1]<<1); for(int i=1;i<=h;i++) for(int j=i+1;j<=h;j++) id[i][j]=++ct; for(int i=1;i<=ct;i++) tl[i][n+1]=N,tr[i][0]=-1; for(int i=1;i<=n;i++) { int u,v,w; cin>>u>>v>>w; if(u>v) swap(u,v); a[id[u][v]].pb(w),tl[id[u][v]][i]=tr[id[u][v]][i]=a[id[u][v]].size(); } for(int i=1;i<=ct;i++) { for(int j=1;j<=n;j++) if(!tr[i][j]) tr[i][j]=tr[i][j-1]; for(int j=n;j>=1;j--) if(!tl[i][j]) tl[i][j]=tl[i][j+1]; } for(int i=1;i<=ct;i++) if(a[i].size()) T[i].build(i,a[i].size()); while(q--) { int l,r; ll res=0; cin>>l>>r; for(int i=1;i<=h;i++) for(int j=i+1;j<=h;j++) { d[i][j]=d[j][i]=inf; int ti=id[i][j]; if(tl[ti][l]<=tr[ti][r]) d[i][j]=d[j][i]=T[ti].query(tl[ti][l],tr[ti][r]); } for(int i=0;i<=h;i++) td[i]=inf,vis[i]=0; td[1]=0; for(int _=1;_<=h;_++) { int x=0; for(int i=1;i<=h;i++) if(!vis[i]&&td[i]<td[x]) x=i; if(!x) {res=-1; break;} res+=td[x],vis[x]=1; for(int i=1;i<=h;i++) if(!vis[i]) td[i]=min(td[i],d[x][i]); } cout<<res<<'\n'; } return 0; } ``` #### Sol.8 ```cpp #include<iostream> #define ll long long using namespace std; const int N=5e5+10; const int M=45+5; const int inf=1e9+1e7; int h,n,q,ct,id[M][M],d[M][M],td[M],ti[N],tw[N],w[N][M]; ll res[N]; bool vis[N]; struct nod{int l,r,id;}a[N],b[N]; void solve(int l,int r,int ql,int qr) { if(l>r||ql>qr) return; if(r-l+1<h-1) {for(int i=ql;i<=qr;i++) res[a[i].id]=-1; return;} if(l==r) {for(int i=ql;i<=qr;i++) res[a[i].id]=tw[l]; return;} int mid=((l+r)>>1),pl=ql,pr=qr; for(int i=mid;i>=l;i--) { if(i<mid) for(int j=1;j<=ct;j++) w[i][j]=w[i+1][j]; else for(int j=1;j<=ct;j++) w[i][j]=inf; w[i][ti[i]]=min(w[i][ti[i]],tw[i]); } for(int i=mid+1;i<=r;i++) { if(i>mid+1) for(int j=1;j<=ct;j++) w[i][j]=w[i-1][j]; else for(int j=1;j<=ct;j++) w[i][j]=inf; w[i][ti[i]]=min(w[i][ti[i]],tw[i]); } for(int i=ql;i<=qr;i++) { if(a[i].l<=mid&&a[i].r>mid) { for(int u=1;u<=h;u++) for(int v=u+1;v<=h;v++) d[u][v]=d[v][u]=min(w[a[i].l][id[u][v]],w[a[i].r][id[u][v]]); for(int u=0;u<=h;u++) td[u]=inf,vis[u]=0; td[1]=0; for(int _=1;_<=h;_++) { int x=0; for(int u=1;u<=h;u++) if(!vis[u]&&td[u]<td[x]) x=u; if(!x) {res[a[i].id]=-1; break;} res[a[i].id]+=td[x],vis[x]=1; for(int v=1;v<=h;v++) if(!vis[v]) td[v]=min(td[v],d[x][v]); } } else if(a[i].r<=mid) b[pl++]=a[i]; else b[pr--]=a[i]; } for(int i=ql;i<pl;i++) a[i]=b[i]; for(int i=pr+1;i<=qr;i++) a[i]=b[i]; solve(l,mid,ql,pl-1),solve(mid+1,r,pr+1,qr); } int main() { ios::sync_with_stdio(false),cin.tie(0),cout.tie(0); cin>>h>>n>>q; for(int i=1;i<=h;i++) for(int j=i+1;j<=h;j++) id[i][j]=++ct; for(int i=1;i<=n;i++) { int u,v; cin>>u>>v>>tw[i]; ti[i]=id[min(u,v)][max(u,v)]; } for(int i=1;i<=q;i++) cin>>a[i].l>>a[i].r,a[i].id=i; solve(1,n,1,q); for(int i=1;i<=q;i++) cout<<res[i]<<'\n'; return 0; } ``` #### Sol.9 ~~~cpp #include<iostream> #define ll long long using namespace std; const int N=5e5+10; const int H=10+3; int h,n,q,ce,tu[N],tv[N],tw[N],f[H],s[H],head[H],t[H],fa[H],fi[H]; ll res[N]; int finds(int x) {return f[x]==x?x:f[x]=finds(f[x]);} bool mg(int x,int y) { x=finds(x),y=finds(y); if(x==y) return false; if(s[x]>s[y]) swap(x,y); s[y]+=s[x],f[x]=y; return true; } struct ask{int l,r,id;}a[N],b[N]; struct edg{int v,id,nxt;}e[H<<1]; void add(int u,int v,int id) {e[++ce]={v,id,head[u]},head[u]=ce;} void dfs(int u,int fat) { for(int i=head[u];i;i=e[i].nxt) { int v=e[i].v,id=e[i].id; if(v!=fat) fa[v]=u,fi[v]=id,dfs(v,u); } } struct nod { int ei[H],c; ll s; void ins(int id) { ce=0; for(int i=1;i<=h;i++) head[i]=0,fa[i]=0; for(int i=0;i<c;i++) { int ti=ei[i],u=tu[ti],v=tv[ti]; add(u,v,ti),add(v,u,ti),t[i]=ti; } int u=tu[id],v=tv[id],w=tw[id],ti=0; dfs(u,0); if(fa[v]) while(v!=u) { if(tw[fi[v]]>tw[ti]) ti=fi[v]; v=fa[v]; } if(!ti||w<tw[ti]) { int tc=c; bool tf=false; c=0; for(int i=0;i<tc;i++) { if(tw[t[i]]>w&&!tf) tf=true,ei[c++]=id; if(t[i]==ti) continue; ei[c++]=t[i]; } if(!tf) ei[c++]=id; } } }c[N]; nod merg(nod a,nod b) { nod r; r.s=r.c=0; int ta=0,tb=0; for(int i=1;i<=h;i++) f[i]=i,s[i]=1; while(ta<a.c&&tb<b.c) { if(r.c==n-1) break; int x=a.ei[ta]; if(tw[b.ei[tb]]<tw[x]) x=b.ei[tb],tb++; else ta++; if(mg(tu[x],tv[x])) r.ei[r.c++]=x,r.s+=tw[x]; } while(r.c<h-1&&ta<a.c) { int x=a.ei[ta]; ta++; if(mg(tu[x],tv[x])) r.ei[r.c++]=x,r.s+=tw[x]; } while(r.c<h-1&&tb<b.c) { int x=b.ei[tb]; tb++; if(mg(tu[x],tv[x])) r.ei[r.c++]=x,r.s+=tw[x]; } return r; } void solve(int l,int r,int ql,int qr) { if(l>r||ql>qr) return; if(r-l+1<h-1) {for(int i=ql;i<=qr;i++) res[a[i].id]=-1; return;} if(l==r) {for(int i=ql;i<=qr;i++) res[a[i].id]=tw[l]; return;} int mid=((l+r)>>1),pl=ql,pr=qr; for(int i=mid;i>=l;i--) { if(i<mid) c[i]=c[i+1]; else c[i].s=c[i].c=0; c[i].ins(i); } for(int i=mid+1;i<=r;i++) { if(i>mid+1) c[i]=c[i-1]; else c[i].s=c[i].c=0; c[i].ins(i); } for(int i=ql;i<=qr;i++) { int l=a[i].l,r=a[i].r,ti=a[i].id; if(l<=mid&&mid<r) { nod tr=merg(c[l],c[r]); res[ti]=(tr.c==h-1?tr.s:-1); } else if(r<=mid) b[pl++]=a[i]; else b[pr--]=a[i]; } for(int i=ql;i<pl;i++) a[i]=b[i]; for(int i=pr+1;i<=qr;i++) a[i]=b[i]; solve(l,mid,ql,pl-1),solve(mid+1,r,pr+1,qr); } int main() { ios::sync_with_stdio(false),cin.tie(0),cout.tie(0); cin>>h>>n>>q; for(int i=1;i<=n;i++) cin>>tu[i]>>tv[i]>>tw[i]; for(int i=1;i<=q;i++) cin>>a[i].l>>a[i].r,a[i].id=i; solve(1,n,1,q); for(int i=1;i<=q;i++) cout<<res[i]<<'\n'; return 0; } ~~~ ### U606785 短恨歌 【数据删除】 ### U606786 花草野 #### Sol.3 ```cpp #include<iostream> #define ll long long #define pll pair<ll,ll> #define fi first #define se second #define lc (u<<1) #define rc (lc|1) #define mid ((l+r)>>1) #define Lc lc,l,mid #define Rc rc,mid+1,r #define U 1,0,n-1 using namespace std; const int N=2e5+10; int n,q; struct nod{ll x,s,d,w;}; struct sgmtt { nod w[N<<2]; int t[N<<2],c[N<<2],s[N<<2]; void pt(int u,ll x,bool f) { if(f) t[u]=0,c[u]=x,w[u]={x,s[u]*x,s[u]*x,s[u]*x*x}; else { t[u]+=x,w[u].w+=(w[u].d+w[u].s+s[u]*x)*x; w[u].x+=x,w[u].s+=s[u]*x,w[u].d+=s[u]*x; } } void Pd(int u) { if(c[u]) pt(lc,c[u],1),pt(rc,c[u],1),c[u]=0; if(t[u]) pt(lc,t[u],0),pt(rc,t[u],0),t[u]=0; } ll Ua(ll pre,int u) { if(pre>=w[u].x) return pre*w[u].s; if(s[u]==1) return w[u].w; Pd(u); return w[lc].x<=pre?w[lc].s*pre+Ua(pre,rc):Ua(pre,lc)+w[u].w-w[lc].w; } ll Ub(ll pre,int u) { if(pre>=w[u].x) return pre*s[u]; if(s[u]==1) return w[u].x; Pd(u); return w[lc].x<=pre?s[lc]*pre+Ub(pre,rc):Ub(pre,lc)+w[u].d-w[lc].d; } void Pu(int u) { w[u].s=w[lc].s+w[rc].s,w[u].x=max(w[lc].x,w[rc].x); w[u].w=w[lc].w+Ua(w[lc].x,rc),w[u].d=w[lc].d+Ub(w[lc].x,rc); } void B(int u,int l,int r) { s[u]=r-l+1; if(l==r) {ll x; cin>>x; w[u]={x,x,x,x*x}; return;} B(Lc),B(Rc),Pu(u); } void C(int u,int l,int r,int L,int R,int x,bool f) { if(l>=L&&r<=R) {pt(u,x,f); return;} Pd(u); if(L<=mid) C(Lc,L,R,x,f); if(R>mid) C(Rc,L,R,x,f); Pu(u); } nod Q(int u,int l,int r,int L,int R,ll pre) { if(l>=L&&r<=R) {nod tr=w[u]; tr.w=Ua(pre,u); return tr;} Pd(u); nod tl={0,0,0,0},tr=tl; if(L<=mid) tl=Q(Lc,L,R,pre); if(R>mid) tr=Q(Rc,L,R,max(pre,tl.x)); return {max(tl.x,tr.x),tl.s+tr.s,tl.d+tr.d,tl.w+tr.w}; } nod Pa(int u,int l,int r,int st,ll x,ll pre) { if(r<st) return {0,-1,0,0}; if(l==r) return {w[u].x,x<=w[u].x*max(pre,w[u].x)?l:-1,0,w[u].x*max(pre,w[u].x)}; Pd(u); if(l>=st) { ll uw=Ua(pre,u),lw=Ua(pre,lc); if(x>uw) return {w[u].x,-1,0,uw}; return x<=lw?Pa(Lc,st,x,pre):Pa(Rc,st,x-lw,max(pre,w[lc].x)); } nod rl=Pa(Lc,st,x,pre),rr; if(rl.s!=-1) return rl; rr=Pa(Rc,st,x-rl.w,max(pre,rl.x)); if(rr.s!=-1) return rr; rr.x=max(rr.x,rl.x),rr.w+=rl.w; return rr; } pll Pb(int u,int l,int r,int st,ll x) { if(r<st) return {-1,0}; if(l==r) return {x<=w[u].s?l:-1,w[u].s}; Pd(u); if(l>=st) { if(x>w[u].s) return {-1,w[u].s}; return x<=w[lc].s?Pb(Lc,st,x):Pb(Rc,st,x-w[lc].s); } pll rl=Pb(Lc,st,x),rr; if(rl.fi!=-1) return rl; rr=Pb(Rc,st,x-rl.se); if(rr.fi!=-1) return rr; rr.se+=rl.se; return rr; } }T; int S() { ll s,x,d=T.w[1].w; cin>>s>>x,x++; if(s) { nod A=T.Q(U,s,n-1,0),B=T.Q(U,0,s-1,A.x); d=A.w+B.w; } if(x<=d) { nod A=T.Pa(U,s,x,0); return A.s==-1?T.Pa(U,0,x-A.w,A.x).s:A.s; } else { int B=T.w[1].x; x=(x-d)%(T.w[1].s*B); ll m=1ll*T.Q(U,s,n-1,0).s*B; if(x<=m) return T.Pb(U,s,(x+B-1)/B).fi; else return T.Pb(U,0,(x-m+B-1)/B).fi; } } int main() { ios::sync_with_stdio(false),cin.tie(0),cout.tie(0); cin>>n>>q,T.B(U); while(q--) { char c; cin>>c; if(c=='Q') cout<<S()<<'\n'; else { int l,r,x; cin>>l>>r>>x; if(l<=r) T.C(U,l,r,x,c=='R'); else T.C(U,0,r,x,c=='R'),T.C(U,l,n-1,x,c=='R'); } } return 0; } ```