bzoj3956: Count(主席树+单调栈)

bzoj3956: Count(主席树+单调栈)

bzoj3956: Count

思路

对友好点对建边的话,可以看出最多只有2n条边,先用单调栈使所有左端点记录右端点,然后对左端点前缀建权值主席树,查询的时候只要判断T[r] - T[l-1] 这颗主席树中有多少点在[l,r]这段区间就行了。

代码

#include <bits/stdc++.h>
using namespace std;
#define dd(x) cout<<#x<<"="<<x<<" "
#define rep(i,a,b) for(int i=(a);i<(b);i++)
#define de(x) cout<<#x<<"="<<x<<"\n"
#define mes(p) memset(p,0,sizeof(p))
#define fi first
#define se second
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define sz(x) (int)x.size()
#define pb push_back
#define ls (rt<<1)
#define rs (ls|1)
#define all(x) x.begin(),x.end()
const int maxn=300005;
typedef long long ll;
typedef vector <int > vi;
typedef pair <int, int> pi;
int n, m, ty, a[maxn], T[maxn], cnt;
struct node{
    int sum, l,r;
    node() {sum=l=r=0;}
}t[maxn<<6]; 
vector <int > v[maxn];
void update(int pre,int &now,int l,int r,int pos){
    now = ++cnt ;
    t[now].sum= t[pre].sum+1;
    if(l==r) return ;
    t[now].l= t[pre].l;
    t[now].r= t[pre].r;
    int mid =l+ r >> 1;
    if(pos <= mid ) update(t[pre].l,t[now].l,l,mid,pos);
    else update(t[pre].r,t[now].r,mid+1,r,pos);
}
int qr(int x,int y,int l,int r,int xx,int yy){
    if(l>=xx &&  r<=yy){
        return t[y].sum-t[x].sum;
    }
    int mid = l+r>>1, s=0;
    if(xx<=mid) s+=qr(t[x].l,t[y].l,l,mid,xx,yy);
    if(mid<yy) s+= qr(t[x].r,t[y].r,mid+1,r,xx,yy);
    return s;
}
int main(){
    scanf("%d%d%d",&n,&m,&ty);
    rep(i,1,n+1) scanf("%d",&a[i]);
    stack< int > s;
    rep(i,1,n+1){
        while(sz(s) &&a[s.top()] <= a[i]) {
            v[s.top()].pb(i);
            s.pop();
        }
        s.push(i);
    }
    while(sz(s)) s.pop();
    for(int i=n;i>0;i--){
        while(sz(s)&& a[s.top()] <= a[i]){
            v[i].pb(s.top());
            s.pop();
        }
        s.push(i);
    }
    rep(i,1,n+1){
        T[i] = T[i-1];
        sort(all(v[i]));
        rep(j,0,sz(v[i]))
        if(!j || v[i][j]!=v[i][j-1])
            update(T[i],T[i],1,n,v[i][j]);
    }
    int last =0 ;
    while(m--){
        int x, y;
        scanf("%d%d",&x,&y);
        if(ty) x=(x+last-1)%n + 1 , y =(y+last-1)%n+1;
        int l = min(x,y);
        y=x+y-l;
        x=l;
        last = qr(T[x-1],T[y],1,n,x,y);
        printf("%d\n",last);
    }
    return 0;
}
posted @ 2019-05-09 00:20  Seast  阅读(157)  评论(0编辑  收藏  举报