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;
}