思路:可以反正 最长重构序列必然符合 此模式 x + { } 与 { } + x
那么 题意转化为了 找两个距离最长的相同的数。eeee 先离散化
然后 开 2e5 个set 可插入可删除的维护 每个数的 出现的位置。
然后 。 如果有set .size > = 2 则可以更新。最值 。最值可用线段树or mulitset 维护
#include<bits/stdc++.h> using namespace std; #define maxn 223456 map<int,int>vis; set<int>val[maxn]; set<int>::iterator it,ib; int tree[maxn*4],n,ans; int t,a[maxn],m,cnt,op,x,y; void up(int root) { tree[root]=max(tree[root*2],tree[root*2+1]); } void updata(int root,int l,int r,int pos,int ad) { if(pos>r||pos<l)return ; if(l==r) { tree[root]=ad; return; } int mid=(l+r)/2; updata(root*2,l,mid,pos,ad); updata(root*2+1,mid+1,r,pos,ad); up(root); } int main() { scanf("%d",&t); while(t--) { vis.clear(); for(int i=0; i<=cnt; i++) val[i].clear(); memset(tree,0,sizeof(tree)); cnt=0; scanf("%d%d",&n,&m); for(int i=1; i<=n; i++) { scanf("%d",&a[i]); if(vis[a[i]]==0) vis[a[i]]=++cnt; val[vis[a[i]]].insert(i); } for(int i=1; i<=cnt; i++) { if(val[i].size()>=2) { ib=--(val[i].end()); it=val[i].begin(); int dd=*ib-*it; updata(1,1,cnt,i,dd); } } while(m--) { scanf("%d",&op); if(op==2) { if(tree[1]<1) printf("-1\n"); else printf("%d\n",tree[1]); } else { scanf("%d%d",&x,&y); val[vis[a[x]]].erase(x); if(val[vis[a[x]]].size()<2) updata(1,1,cnt,vis[a[x]],0); else { ib=--(val[vis[a[x]]].end()); it=val[vis[a[x]]].begin(); int dd=*ib-*it; updata(1,1,cnt,vis[a[x]],dd); } a[x]=y; if(vis[y]==0) vis[y]=++cnt; val[vis[y]].insert(x); if(val[vis[a[x]]].size()<2) updata(1,1,cnt,vis[a[x]],0); else { ib=--(val[vis[a[x]]].end()); it=val[vis[a[x]]].begin(); int dd=*ib-*it; updata(1,1,cnt,vis[a[x]],dd); } } } } return 0; }