BZOJ-3524 [POI2014]Couriers
树状数组套权值线段树,然后对于每个询问进行二分答案。
#include <cstdlib> #include <cstdio> #include <cctype> #include <cstring> #include <cmath> #include <iostream> #include <algorithm> #define rep(i, l, r) for(int i=l; i<=r; i++) #define clr(x, c) memset(x, c, sizeof(x)) #define lowbit(x) (x&-x) #define maxn 500009 #define maxm 10000009 #define inf 0x7fffffff #define s(x) Sum[x] #define t(x) Tree[x] #define l(x) Left[x] #define r(x) Right[x] using namespace std; inline int read() { int x=0, f=1; char ch=getchar(); while (!isdigit(ch)) {if (ch=='-') f=-1; ch=getchar();} while (isdigit(ch)) x=x*10+ch-'0', ch=getchar(); return x*f; } int n, m, z, Tree[maxn], Left[maxm], Right[maxm], Sum[maxm]; void Add(int k, int l, int r, int u, int &t) { if (!t) t=++z; s(t)=s(u)+1; if (l==r) return; int mid=(l+r)>>1; if (k<=mid) r(t)=r(u), Add(k, l, mid, l(u), l(t)); else l(t)=l(u), Add(k, mid+1, r, r(u), r(t)); } inline int Query(int l, int r) { int tmp=(r-l+1)/2, L=1, R=n, x=t(l-1), y=t(r); while (L<R) { if (s(y)-s(x)<=tmp) return 0; int mid=(L+R)>>1; if (s(l(y))-s(l(x))>tmp) R=mid, x=l(x), y=l(y); else if (s(r(y))-s(r(x))>tmp) L=mid+1, x=r(x), y=r(y); else return 0; } return L; } int main() { n=read(), m=read(); t(0)=++z, l(z)=r(z)=z; rep(i, 1, n) Add(read(), 1, n, t(i-1), t(i)); rep(i, 1, m) { int l=read(), r=read(); printf("%d\n", Query(l, r)); } return 0; }