与众不同
线段树 最长互异子段
正文
// 原题:https://oj.yecheng.tv/p/T1543
// 题意:N 个月盈利值、M 次询问;每次问区间[L,R]内最长"完美序列"(连续互异)长度。
// 思路:预处理 running start[i]=以 i 结尾最长互异段起点、f[i]=其长度;两棵线段树分别求被 L 截断的两种贡献取最大。
// 复杂度:O(N log N + M log^2 N) 时间 / O(N log N) 空间
// 易错点:下标 0-based;当 start[i]<L 时该点有效长度受窗口左端 L 限制。
#include <bits/stdc++.h>
using namespace std;
const int MAXN=200005;
int a[MAXN], left_[MAXN], f[MAXN];
vector<pair<int,int>> nodeA[4*MAXN];
vector<int> smaxA[4*MAXN];
int minL[4*MAXN];
void buildA(int id,int l,int r){
if(l==r){
nodeA[id].push_back({left_[l],f[l]});
smaxA[id].push_back(f[l]);
return;
}
int mid=(l+r)/2;
buildA(id*2,l,mid);
buildA(id*2+1,mid+1,r);
auto &L=nodeA[id*2], &R=nodeA[id*2+1];
int i=0,j=0;
while(i<(int)L.size()||j<(int)R.size()){
pair<int,int> cur;
if(j==(int)R.size()||(i<(int)L.size()&&L[i].first<=R[j].first))cur=L[i++];
else cur=R[j++];
nodeA[id].push_back(cur);
}
int m=nodeA[id].size();
smaxA[id].assign(m,0);
for(int k=m-1;k>=0;k--)
smaxA[id][k]=max(nodeA[id][k].second,(k+1<m?smaxA[id][k+1]:0));
}
int queryA(int id,int l,int r,int ql,int qr,int L0){
if(ql>r||qr<l)return 0;
if(ql<=l&&r<=qr){
auto &v=nodeA[id];
int lo=lower_bound(v.begin(),v.end(),make_pair(L0,0))-v.begin();
if(lo>=(int)v.size())return 0;
return smaxA[id][lo];
}
int mid=(l+r)/2;
return max(queryA(id*2,l,mid,ql,qr,L0),queryA(id*2+1,mid+1,r,ql,qr,L0));
}
void buildB(int id,int l,int r){
if(l==r){minL[id]=left_[l];return;}
int mid=(l+r)/2;
buildB(id*2,l,mid);
buildB(id*2+1,mid+1,r);
minL[id]=min(minL[id*2],minL[id*2+1]);
}
int findRight(int id,int l,int r,int ql,int qr,int L0){
if(ql>r||qr<l||minL[id]>=L0)return -1;
if(l==r)return l;
int mid=(l+r)/2;
int res=findRight(id*2+1,mid+1,r,ql,qr,L0);
if(res!=-1)return res;
return findRight(id*2,l,mid,ql,qr,L0);
}
int main(){
int N,M;
if(!(cin>>N>>M))return 0;
map<int,int> last;
int start=0;
for(int i=0;i<N;i++){
cin>>a[i];
if(last.count(a[i]))start=max(start,last[a[i]]+1);
left_[i]=start;
f[i]=i-start+1;
last[a[i]]=i;
}
buildA(1,0,N-1);
buildB(1,0,N-1);
while(M--){
int L,R;cin>>L>>R;
int p1=queryA(1,0,N-1,L,R,L);
int idx=findRight(1,0,N-1,L,R,L);
int p2=(idx!=-1)?(idx-L+1):0;
cout<<max(p1,p2)<<"\n";
}
return 0;
}
一本通·提高篇的其它内容
- 活动安排
- 种树
- 喷水装置
- 加工生产调度
- 智力大冲浪
- 数列极差
- 数列分段
- 线段
- 家庭作业
- 钓鱼
- 糖果传递
- 愤怒的牛
- Best Cow Fences
- 曲线
- 数列分段 II
- 扩散
- 灯泡
- 传送带
- 数的划分
- 生日蛋糕
- 小木棍
- Addition Chains
- 埃及分数
- 平板涂色
- 质数方阵
- 靶形数独
- 电路维修
- 魔板
- Knight Moves
- 棋盘游戏
- Keyboarding
- 移动玩具
- 山峰和山谷
- Oulipo
- 图书管理
- Power Strings
- Seekthe Name, Seek the Fame
- Friends
- A Horrible Poem
- Beads
- Antisymmetry
- 门票
- 收集雪花
- 剪花布条
- Power Strings
- Radio Transmission
- OKR-Periods of Words
- 似乎在梦中见过的样子
- Censoring
- Phone List
- The XOR Largest Pair
- Nikitosh 和异或
- Immediate Decodability
- L 语言
- Secret Message 秘密信息
- 背单词
- The Xor-longest Path
- Keywords Search
- 玄武密码
- Censoring