Codeforces Round #716 (Div. 2) D.Cut and Stick 【线段树、二分统计数量】


原题链接:D. Cut and Stick (codeforces.com)

题意:给定一个长度为 n 的数组,以及 q 次区间查询,每次需输出询问区间的最小分裂数

思路:用线段树维护众数,二分求区间内众数的数量

评价:二分+线段树

 1 #include 
 2 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 }