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

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

bzoj3956: Count

思路

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

代码

#include 
using namespace std;
#define dd(x) cout<<#x<<"="< vi;
typedef pair  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  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 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;
}

你可能感兴趣的:(bzoj3956: Count(主席树+单调栈))