Codeforces 323 C Two permutations 题解(主席树)

题目:CF 323 C.
题目大意:给定两个长度为 n n n的排列 a , b a,b a,b,每次询问有多少个数 a [ l 1.. r 1 ] a[l1..r1] a[l1..r1] b [ l 2.. r 2 ] b[l2..r2] b[l2..r2]中同时出现.
设询问次数为 n n n,则 1 ≤ n ≤ 1 0 6 , 1 ≤ m ≤ 2 ∗ 1 0 5 1\leq n\leq 10^6,1\leq m\leq 2*10^5 1n106,1m2105.

首先很显然我们要把 b b b中每一个数在 a a a中的出现位置记录下来.

考虑一个简化的问题,若 l 2 = 1 , r 2 = n l2=1,r2=n l2=1,r2=n,那么我们现在开一个数组 c n t [ i ] cnt[i] cnt[i]表示 a [ i ] a[i] a[i]的出现数量,那么答案即为 ∑ i = l 1 r 1 c n t [ i ] \sum_{i=l1}^{r1}cnt[i] i=l1r1cnt[i],建立线段树维护即可(我知道这个值一定是 r 1 − l 1 + 1 r1-l1+1 r1l1+1,但是我们要对下面的解法有所提示).

若有了 b b b的区间限制,那么考虑把维护 c n t cnt cnt数组的线段树换成主席树,第 i i i棵主席树维护 l 2 = 1 , r 2 = i l2=1,r2=i l2=1,r2=i时的 c n t cnt cnt数组.

代码如下:

#include<bits/stdc++.h>
  using namespace std;

#define Abigail inline void
typedef long long LL;

const int N=1000000,C=24;

int ri(){
  int x=0;
  char c=getchar();
  for (;c<'0'||c>'9';c=getchar());
  for (;c<='9'&&c>='0';c=getchar()) x=x*10+c-'0';
  return x;
}

int n,b[N+9],ord[N+9];
struct tree{
  int l,r,sum,ls,rs;
}tr[N*C+9];
int rot[N+9],cn,ans;

void Pushup(int k){tr[k].sum=tr[tr[k].ls].sum+tr[tr[k].rs].sum;}

int Build(int L,int R){
  int now=++cn;
  tr[now].l=L;tr[now].r=R;
  if (L==R) return now;
  int mid=L+R>>1;
  tr[now].ls=Build(L,mid);tr[now].rs=Build(mid+1,R);
  return now;
}

int Add_tree(int k,int x){
  int now=++cn;tr[now]=tr[k];
  if (tr[k].l==tr[k].r){++tr[now].sum;return now;}
  int mid=tr[k].l+tr[k].r>>1;
  if (x<=mid) tr[now].ls=Add_tree(tr[k].ls,x);
  else tr[now].rs=Add_tree(tr[k].rs,x);
  Pushup(now);
  return now;
}

int Query(int L,int R,int k){
  if (L==tr[k].l&&R==tr[k].r) return tr[k].sum;
  int mid=tr[k].l+tr[k].r>>1;
  if (R<=mid) return Query(L,R,tr[k].ls);
  else if (L>mid) return Query(L,R,tr[k].rs);
    else return Query(L,mid,tr[k].ls)+Query(mid+1,R,tr[k].rs); 
}

int f(int x){return (x-1+ans)%n+1;}

Abigail into(){
  n=ri();
  for (int i=1;i<=n;++i)
    ord[ri()]=i;
  for (int i=1;i<=n;++i)
    b[i]=ord[ri()];
}

Abigail work(){
  rot[0]=Build(1,n);
  for (int i=1;i<=n;++i)
    rot[i]=Add_tree(rot[i-1],b[i]);
}

Abigail getans(){
  int m,l1,r1,l2,r2;
  m=ri();
  for (int i=1;i<=m;++i){
  	l1=f(ri());r1=f(ri());l2=f(ri());r2=f(ri());
  	if (l1>r1) swap(l1,r1);if (l2>r2) swap(l2,r2);
  	printf("%d\n",ans=Query(l1,r1,rot[r2])-Query(l1,r1,rot[l2-1]));++ans;
  }
}

int main(){
  into();
  work();
  getans();
  return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值