HDU 6070 線段樹
阿新 • • 發佈:2017-08-04
const cnblogs 分析 2.0 新的 add ans ast main
題意:求AC率,x/y 的最小值,x是區間數字的種類數,y是區間的長度。
分析:
二分答案比率。ans,
動態插入結點,一些區間的size會發生變化,是那些前面暫時沒有新的結點的區間 size + 1。
ans*l,每一個區間只有一個ans*l,只與 l 相關,線段樹單點更新。
用線段樹維護區間的最小值。最小值小於 ans,二分左移。
#include <bits/stdc++.h> using namespace std; const int maxn = 60005; const int eps = 1e-9; int a[maxn]; int last[maxn];double tree[maxn<<2],add[maxn<<2]; void pushdown(int root) { tree[root<<1]+=add[root]; tree[root<<1|1]+=add[root]; add[root<<1]+=add[root]; add[root<<1|1]+=add[root]; add[root]=0; } void update(int l,int r,int L,int R,int root,doublek) { if(l<=L&&R<=r) { tree[root]+=k; add[root]+=k; return ; } if(add[root]>eps)pushdown(root); int mid=L+R>>1; if(r<=mid)update(l,r,L,mid,root<<1,k); else if(l>mid)update(l,r,mid+1,R,root<<1|1,k);else { update(l,mid,L,mid,root<<1,k); update(mid+1,r,mid+1,R,root<<1|1,k); } tree[root]=min(tree[root<<1],tree[root<<1|1]); } double query(int l,int r,int L,int R,int root) { if(l<=L&&R<=r) return tree[root]; if(add[root]>eps)pushdown(root); int mid=L+R>>1; if(r<=mid)return query(l,r,L,mid,root<<1); else if(l>mid)return query(l,r,mid+1,R,root<<1|1); else return min(query(l,mid,L,mid,root<<1),query(mid+1,r,mid+1,R,root<<1|1)); tree[root]=min(tree[root<<1],tree[root<<1|1]); } int main() { //freopen("in.txt","r",stdin); int t; scanf("%d",&t); while(t--) { int n; scanf("%d",&n); for(int i=1; i<=n; i++) scanf("%d",&a[i]); double l = 0,r=1.0; for(int g=0; g<20; g++) { double mid = (l+r)/2.0; memset(tree,0,sizeof(tree)); memset(add,0,sizeof(add)); memset(last,0,sizeof(last)); int flag = 0; for(int i=1; i<=n; i++) { update(last[a[i]]+1,i,1,n,1,1); update(i,i,1,n,1,mid*i); last[a[i]] = i; double k = query(1,i,1,n,1); if(k<=(double)mid*(i+1)) { flag=1; break; } } if(flag!=1) l = mid; else r = mid; } printf("%.10lf\n",l); } return 0; }
HDU 6070 線段樹