HDU 6070 Binary Search+Line Segment Tree+Enumeration

Posted by jwer78 on Sat, 08 Jun 2019 00:12:00 +0200

Binary Search + Line Segment Tree + Enumeration

Topic:

In the ACM-ICPC competition, there will be many different situations in submitting a topic. Now we give all the submissions of a team. Only AC and WA are given in sequence. The last time the same number appears is AC, which defines an interval.

DirtRatio=cnt(AC)/sum(submit)

That is to say, divide the number of AC in the whole interval by the total number of submissions, and find out what the minimum ratio is.

Ideas:

In fact, the meaning of the question is not very clear. The range of the number given is 1-60000, and any sub-interval can be submitted as a complete topic. That is to say, the number of AC is the total number of different numbers appearing in the sub-interval, and the length of the interval is the total number of submissions. I was wrong when I understood, but fortunately there was discuss ion... Nevertheless, I didn't expect such a powerful line segment tree method.

There are many sub-intervals in the range of 60,000, so we can't write violently! __________ Dirt Ratio ranges from 0 to 1, and the accuracy is

10−4
So next time you come across such a question, you can choose to use dichotomy.

Definition:

size(l,r)
Interval
[l,r]
So there are the number of questions that have already been AC.
size(l,r)/(r−l+1)=mid
After simplification
size(l,r)+mid∗l=mid∗(r+1)
Careful observation shows that if R is fixed for each size(l,r)+mid l, each interval L is a variable, and if the line segment tree is used to maintain the size of L to R interval, L is fixed for the sub-interval, because only 1-r-1 interval is the target interval, then the line segment tree maintains the size(l,r)+mid L of each l to R interval, so enumerate r when R is determined. It is only necessary to find the minimum size(l,r)+mid l of 1~r-1 in the line segment tree to determine whether mid is valid. The way to enumerate R is to insert a new R every time. The effect of R on size is to add the size(l, r) to the interval with R as the right endpoint, i.e. size(l,r)+mid l to 1 if there is no a[r].
#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;

const int maxn = 60005;
const int INF = 0x3f3f3f3f;
const double eps = 1e-5;

int n;
int a[maxn],lastAppear[maxn];

struct Node
{
    int l,r;
    double sum;
    double lazy;
}tree[maxn<<2];

void Push_up(int root)
{
    tree[root].sum = min(tree[root<<1].sum,tree[root<<1|1].sum);
}
void Push_down(int root)
{
    tree[root<<1].sum += tree[root].lazy;
    tree[root<<1].lazy += tree[root].lazy;
    tree[root<<1|1].sum += tree[root].lazy;
    tree[root<<1|1].lazy += tree[root].lazy;
    tree[root].lazy = 0;
}

void build(int root,int l,int r,double v)
{
    tree[root].l = l,tree[root].r = r;
    tree[root].lazy = 0;
    if(l == r) {
        tree[root].sum = (long long)l*v;
        return ;
    }
    int mid = (l+r)>>1;
    build(root<<1,l,mid,v);
    build(root<<1|1,mid+1,r,v);
    Push_up(root);
}

void UpDate(int L,int R,int root,int v)
{
    if(L <= tree[root].l && tree[root].r <= R) {
        tree[root].sum += v;
        tree[root].lazy += v;       /*lazy Let the sum of subintervals increase v as a whole, so sum += v*/
        return ;
    }
    if(tree[root].lazy != 0) Push_down(root);
    int mid = (tree[root].l + tree[root].r)>>1;
    if(L <= mid) UpDate(L,R,root<<1,v);
    if(R > mid) UpDate(L,R,root<<1|1,v);
    Push_up(root);
}

double queryMinSum(int L,int R,int root)
{
    if(L <= tree[root].l && tree[root].r <= R) {
        return tree[root].sum;
    }
    if(tree[root].lazy != 0) Push_down(root);
    double ans = INF;
    int mid = (tree[root].l + tree[root].r)>>1;
    if(L <= mid) ans = queryMinSum(L,R,root<<1);
    if(R > mid)  {
        double temp = queryMinSum(L,R,root<<1|1);
        if(temp < ans)
            ans = temp;
    }
    return ans;
}

int judge(double mid)
{
    build(1,1,n,mid);       /*More mid than conventional tree building, in fact, is a perfect pretreatment*/
    for(int i = 1;i <= n; i++) lastAppear[i] = 0;
    for(int i = 1;i <= n; i++) {
        UpDate(lastAppear[a[i]]+1,i,1,1);
        lastAppear[a[i]] = i;
        if(queryMinSum(1,i,1) <= mid*(i+1)) return true;
    }
    return false;
}

int main(int argc, char const *argv[])
{
    //freopen("in.txt","r",stdin);

    int tt;
    scanf("%d",&tt);
    while(tt--) {
        scanf("%d",&n);
        for(int i = 1;i <= n; i++) scanf("%d",&a[i]);
        double l = 0,r = 1,mid,ans;
        while(r - l > eps) {
            mid = (r+l)/2;
            if(judge(mid)) r = (ans = mid) - eps;
            else l = mid + eps;
        }
        printf("%.9f\n",ans);
    }
    return 0;
}