一万年前抄的代码,今天复习一蛤主席树,这题又不会了
这题是求一段区间中每个数字出现的第一次的位置是在哪
直接正着做的话要二分一蛤位置,题解都说过不去
所以学习了神奇的做法,倒着加链,这题不是求,每个节点存从rt位置开始在那个区间有多少个第一次出现的数字,那么求l-r中的就是从rt[l]下去求一蛤l-r中第一次的数字总数k,然后(k+1)/2下去找。
#include<bits/stdc++.h>
#define maxl 200010
using namespace std;
int n,m,cas,tot;
int a[maxl],rt[maxl],pre[maxl],ans[maxl];
struct node
{
int ls,rs,sum;
}tree[maxl*40];
inline void add(int &x,int y,int pos,int d,int l,int r)
{
tree[++tot]=tree[y];x=tot;
tree[x].sum+=d;
if(l==r)
return;
int mid=(l+r)>>1;
if(pos<=mid)
add(tree[x].ls,tree[y].ls,pos,d,l,mid);
else
add(tree[x].rs,tree[y].rs,pos,d,mid+1,r);
}
inline void prework()
{
memset(pre,-1,sizeof(pre));
memset(rt,0,sizeof(rt));
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
tot=0;
for(int i=n;i>=1;i--)
{
if(pre[a[i]]<0)
add(rt[i],rt[i+1],i,1,1,n);
else
{
int tmp;
add(tmp,rt[i+1],pre[a[i]],-1,1,n);
add(rt[i],tmp,i,1,1,n);
}
pre[a[i]]=i;
}
}
inline int query(int x,int l,int r,int l1,int r1)
{
if(l1==l && r1==r)
return tree[x].sum;
int mid=(l+r)>>1;
if(r1<=mid)
return query(tree[x].ls,l,mid,l1,r1);
else
if(l1>mid)
return query(tree[x].rs,mid+1,r,l1,r1);
else
return query(tree[x].ls,l,mid,l1,mid)+query(tree[x].rs,mid+1,r,mid+1,r1);
}
inline int solve(int x,int l,int r,int k)
{
if(l==r)
return l;
int mid=(l+r)>>1,tp=tree[tree[x].ls].sum;
if(k<=tp)
return solve(tree[x].ls,l,mid,k);
else
return solve(tree[x].rs,mid+1,r,k-tp);
}
inline void mainwork()
{
int l,r,sum,k;
for(int i=1;i<=m;i++)
{
scanf("%d%d",&l,&r);
l=(l+ans[i-1])%n+1;
r=(r+ans[i-1])%n+1;
if(l>r)
swap(l,r);
k=query(rt[l],1,n,l,r);
ans[i]=solve(rt[l],1,n,(k+1)/2);
}
}
inline void print()
{
printf("Case #%d:",cas);
for(int i=1;i<=m;i++)
printf(" %d",ans[i]);
printf("\n");
}
int main()
{
int t;
scanf("%d",&t);
for(cas=1;cas<=t;cas++)
{
prework();
mainwork();
print();
}
return 0;
}