题解:P7719 「EZEC-10」多彩的线段
C1942huangjiaxu · · 题解
对于询问,贪心的从左到右扫一遍,每次选出当前左端点往右覆盖最长的线段。
对于每个
我们把
先考虑怎么求出
设
同时可以发现,
这部分预处理的时间复杂度为
但是
如果一条链满足,链中每个点到它父亲的距离一样,就可以进行缩点,仅保留链底,链顶,以及相邻两点的距离,这样我们仍然可以求出每个点在树上的深度。
如果一段区间
我们称保留下来的点为关键点,通过之前的预处理可以发现,长度为
求出关键点后,考虑如何建树,我们需要找到每个关键点缩点后的父亲。因为原树每条边的长度
对于询问
时间复杂度
参考代码:
#include<bits/stdc++.h>
using namespace std;
const int N=4e6+5;
#define fi first
#define se second
char buf[1<<23],*p1=buf,*p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<23,stdin),p1==p2)?EOF:*p1++)
template<class rd>
void read(rd &x){
char c=getchar();
for(;c<48||c>57;c=getchar());
for(x=0;c>47&&c<58;c=getchar())x=(x<<1)+(x<<3)+(c^48);
}
int ty,n,m,q,d[N],p[N],dp[N],ct,Ans,in[N],out[N];
vector<int>e[N];
vector<pair<int,int> >vc[12],tt;
void dfs(int x){
in[x]=++in[0];
for(auto v:e[x])dfs(v);
out[x]=in[0];
}
int main(){
read(ty),read(n),read(m),read(q);
for(int i=1,l,r,k;i<=m;++i){
read(l),read(r),read(k);
for(int j=1;j<=k;++j)vc[j].emplace_back(l,r-j);
}
for(int j=10;j;--j){
sort(vc[j].begin(),vc[j].end());
vector<pair<int,int> >tmp;
for(int i=0;i<vc[j].size();++i){
auto [l,r]=vc[j][i];
while(i+1<vc[j].size()&&vc[j][i+1].fi<=r+1)++i,r=max(r,vc[j][i].se);
tmp.emplace_back(l,r);
}
vc[j]=tmp;
for(int i=0,o=0;i<vc[j].size();++i){
auto [l,r]=vc[j][i];
while(l<=r){
while(o<vc[j+1].size()&&vc[j+1][o].fi<l)++o;
if(o<vc[j+1].size()){
if(vc[j+1][o].fi>r){
tt.emplace_back(l,j);
break;
}
if(vc[j+1][o].fi>l)tt.emplace_back(l,j);
l=vc[j+1][o].se+1;
}else{
tt.emplace_back(l,j);
break;
}
}
}
}
sort(tt.begin(),tt.end());
tt.emplace_back(n,0);
for(int i=0;i+1<tt.size();++i){
int lim=tt[i].fi+tt[i].se;
if(i&&tt[i-1].se>tt[i].se)++lim;
lim=min(lim,tt[i+1].fi);
for(int j=tt[i].fi;j<lim;++j)
++ct,p[ct]=j,d[ct]=tt[i].se;
}
p[++ct]=n;
for(int i=ct-1;i;--i)
for(int j=i+1;;++j)if((p[j]-p[i])%d[i]==0){
e[j].emplace_back(i),dp[i]=dp[j]+(p[j]-p[i])/d[i];
break;
}
dfs(ct);
for(int i=1,a,b;i<=q;++i){
read(a),read(b);
if(ty)a^=Ans,b^=Ans;
int u=upper_bound(p+1,p+ct+1,a)-p-1,v=upper_bound(p+1,p+ct+1,b)-p-1;
while((a-p[u])%d[u]!=0)--u;
Ans=-(a-p[u])/d[u];
while(in[u]<in[v]||in[u]>out[v])--v;
Ans+=dp[u]-dp[v];
if(b!=p[v])Ans+=(b-p[v]-1)/d[v]+1;
printf("%d\n",Ans);
}
return 0;
}