Peaks 题解
Peaks题解
浅提离线算法
将询问按照
求第
在线做法
其实题目描述已经很明显了,Debug难度也不太大,只要学会主席树和Kruskal重构树即可。
每次询问都要求走权值小于等于一个值
我们可以按叶子节点DFS序的大小,将所有的叶子节点排成一个序列,这样一个子树内的所有叶子节点的编号都是连续的。那么将这个序列的所有点的海拔建成一棵主席树,这样,对于每次询问,我们都将符合条件的祖先挑出来,查询它的子树中DFN序最小的记为
代码(强制在线)
/*
* Author:Ehundategh
* Update:2023/10/4
* Title:P7834.cpp
* You steal,I kill
*/
#include <cstdio>
#include <cstring>
#include <algorithm>
#define MAXN 100010
#define MAXM 500010
#define LSon Node[Now].LeftS
#define RSon Node[Now].RightS
using namespace std;
int DS_Fa[MAXN<<1],n,m,Q,cnt,Fa[MAXN<<1][23],Height[MAXN];
int LastAns=0;
int Line[MAXN],CopyL[MAXN],Count=0,Roots[MAXN],Look[MAXN],cnl=0;
struct edge{
int St,Ed;
int Value;
}Edge[MAXM];
bool cmp(edge a,edge b){
return a.Value<b.Value;
}
int Find(int a){return DS_Fa[a]==a?DS_Fa[a]:DS_Fa[a]=Find(DS_Fa[a]);}
struct node{
int LeftS,RightS;
int Value,Left,Right,Father;
}Node[MAXN<<1];
void Merge(int a,int b,int c){
Node[Find(a)].Father=c;
Node[Find(b)].Father=c;
Node[c].LeftS=Find(a);
Node[c].RightS=Find(b);
Fa[Find(a)][0]=c;
Fa[Find(b)][0]=c;
DS_Fa[Find(a)]=c;
DS_Fa[Find(b)]=c;
}
void Rebuild(){
sort(Edge+1,Edge+m+1,cmp);
for(int i=1;i<=2*n;i++) DS_Fa[i]=i;
for(int i=1;i<=m;i++){
if(Find(Edge[i].St)==Find(Edge[i].Ed)) continue;
Merge(Edge[i].St,Edge[i].Ed,++cnt);
Node[cnt].Value=Edge[i].Value;
}
}
void Init(){
for(int i=1;i<=21;i++){
for(int j=1;j<=cnt;j++){
Fa[j][i]=Fa[Fa[j][i-1]][i-1];
}
}
}
void ReMark(int Now){
if(Now<=n){
Line[++Count]=Height[Now];
CopyL[Count]=Height[Now];
Node[Now].Left=Node[Now].Right=Count;
return;
}
ReMark(LSon); ReMark(RSon);
Node[Now].Left=min(Node[LSon].Left,Node[RSon].Left);
Node[Now].Right=max(Node[LSon].Right,Node[RSon].Right);
}
void Ans(int St,int Top,int &Left,int &Right){
for(int i=21;i>=0;i--){
if(Node[Fa[St][i]].Value<=Top) St=Fa[St][i];
}
Left=Node[St].Left;
Right=Node[St].Right;
return;
}
void Discrete(){
sort(CopyL+1,CopyL+n+1);
for(int i=1;i<=n;i++){
if(i==1||CopyL[i]!=CopyL[i-1]){
Look[++cnl]=CopyL[i];
}
}
}
int DFind(int x){
return lower_bound(Look+1,Look+cnl+1,x)-Look;
}
class President_Tree{
private:
struct n{
int Left,Right;
int Sum;
}T[MAXN<<5];
public:
int New_Tree(int Last,int Left,int Right,int Value){
int Root=++cnt;
T[Root].Left=T[Last].Left;
T[Root].Right=T[Last].Right;
T[Root].Sum=T[Last].Sum+1;
int Mid=(Left+Right)/2;
if(Left!=Right){
if(Value<=Mid){T[Root].Left=New_Tree(T[Last].Left,Left,Mid,Value);}
else{T[Root].Right=New_Tree(T[Last].Right,Mid+1,Right,Value);}
}
return Root;
}
int Query(int Rank,int PeriodLeft,int PeriodRight,int Left,int Right){
if(Left==Right) return Left;
int Now=T[T[PeriodRight].Left].Sum-T[T[PeriodLeft].Left].Sum;
int Mid=(Left+Right)/2;
if(Now>=Rank){
return Query(Rank,T[PeriodLeft].Left,T[PeriodRight].Left,Left,Mid);
}
else{
return Query(Rank-Now,T[PeriodLeft].Right,T[PeriodRight].Right,Mid+1,Right);
}
}
}Tree;
int main(){
scanf("%d%d%d",&n,&m,&Q);
for(int i=1;i<=n;i++){
scanf("%d",&Height[i]);
}
for(int i=1;i<=m;i++){
scanf("%d%d%d",&Edge[i].St,&Edge[i].Ed,&Edge[i].Value);
}
cnt=n;
Rebuild();
ReMark(cnt);
Fa[cnt][0]=cnt;
Init();
Discrete();
for(int i=1;i<=Count;i++){
Roots[i]=Tree.New_Tree(Roots[i-1],1,cnl,DFind(Line[i]));
}
while(Q-->0){
int In1,In2,In3,L,R;
scanf("%d%d%d",&In1,&In2,&In3);
In1=((In1^LastAns)%n)+1;
In3=((In3^LastAns)%n)+1;
In2=In2^LastAns;
Ans(In1,In2,L,R);
if(R-L+1<In3) {LastAns=0; printf("-1\n"); }
else {
LastAns=Look[Tree.Query(R-L+2-In3,Roots[L-1],Roots[R],1,cnl)];
printf("%d\n",LastAns);
}
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探