SSP Round 题解
KSCD_
·
·
题解
前言
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_i 且 res\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+1 在 l\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_L 和 g_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;
}
```