Codeforces Round #716 (Div. 2) D.Cut and Stick 【线段树、二分统计数量】
原题链接:D. Cut and Stick (codeforces.com)
题意:给定一个长度为 n 的数组,以及 q 次区间查询,每次需输出询问区间的最小分裂数
思路:用线段树维护众数,二分求区间内众数的数量
评价:二分+线段树
1 #include2 using namespace std; 3 //#define mod 1000000007 4 #define pb push_back 5 typedef long long ll; 6 int n,q,a[300005]; 7 vector<int> pos[300005]; 8 struct node 9 { 10 int l,r,ma; 11 }tr[1200020]; 12 int count(int x,int l,int r) 13 { 14 return upper_bound(pos[x].begin(),pos[x].end(),r)-lower_bound(pos[x].begin(),pos[x].end(),l); 15 } 16 void pushup(int u) 17 { 18 tr[u].ma=(count(tr[u<<1].ma,tr[u].l,tr[u].r)>count(tr[u<<1|1].ma,tr[u].l,tr[u].r))?tr[u<<1].ma:tr[u<<1|1].ma; 19 } 20 void build(int u,int l,int r) 21 { 22 tr[u].l=l; 23 tr[u].r=r; 24 if(l==r) {tr[u].ma=a[r];return;} 25 int mid=(tr[u].l+tr[u].r)/2; 26 build(u<<1,l,mid); 27 build(u<<1|1,mid+1,r); 28 pushup(u); 29 //printf("test %d %d %d\n",tr[u].l,tr[u].r,tr[u].ma); 30 } 31 int query(int u,int l,int r) 32 { 33 if(tr[u].l>=l&&tr[u].r<=r) return count(tr[u].ma,l,r); 34 else 35 { 36 int res1=0,res2=0; 37 int mid=(tr[u].l+tr[u].r)/2; 38 if(l<=mid) res1=query(u<<1,l,r); 39 if(r>mid) res2=query(u<<1|1,l,r); 40 return max(res1,res2); 41 } 42 } 43 int main() 44 { 45 scanf("%d%d",&n,&q); 46 for(int i=1;i<=n;i++) 47 { 48 scanf("%d",&a[i]); 49 pos[a[i]].pb(i); 50 } 51 build(1,1,n); 52 while(q--) 53 { 54 int l,r; 55 scanf("%d%d",&l,&r); 56 //printf("%d\n",query(1,l,r)); 57 printf("%d\n",max(1,2*query(1,l,r)-(r-l+1))); 58 } 59 return 0; 60 }