51Nod 1461 - 穩定桌(列舉+線段樹)
阿新 • • 發佈:2019-01-13
【題目描述】
【思路】
線段樹還是寫的少,不知道還有這樣子的用法
看了別人的題解,這道題是要列舉所有的長度,然後計算把當前長度作為最長桌腿時消耗的最小代價,取最小值就是答案. 當列舉某個長度
時,要把比
長的桌腿都刪掉,這個可以用代價的字首和處理. 然後看一看現在長度為
的桌腿有沒有超過剩下桌腿的一半,超過了直接更新答案,如果沒超過那麼還要刪掉一定數量的長度比
小的桌腿,這裡用一個線段樹來作為一個集合儲存長度
的桌腿的數量以及代價和,線段樹的區間表示的意義就是代價,維護的是一段代價區間總和,即桌腿在這個代價區間裡的總數量和總代價和,這樣可以用查詢操作查出代價前
小的桌腿的代價總和
#include<bits/stdc++.h> #define max(a,b)(a>b?a:b) #define min(a,b)(a<b?a:b) #define node tree[id] #define lson tree[id<<1] #define rson tree[id<<1|1] using namespace std; typedef long long ll; const ll inf=1e18; const int maxn=1e5+50; struct Tree{ int left,right; int num; ll sum; }; int n; int a[maxn],b[maxn],maxa,maxb;\ vector<int> g[maxn];//g[i]記錄長度為i的桌腿代價分別為多少 ll c[maxn],s[maxn];//c[i]是數量字首和,s[i]是代價字首和 Tree tree[maxn<<2]; void pushup(int id){ node.num=lson.num+rson.num; node.sum=lson.sum+rson.sum; } void build(int id,int le,int ri){ node.left=le; node.right=ri; node.num=0; node.sum=0; if(le==ri) return; int mid=(le+ri)>>1; build(id<<1,le,mid); build(id<<1|1,mid+1,ri); } void update(int id,int d){//增加一個代價為d的桌腿 if(node.left==node.right){ ++node.num; node.sum+=d; return; } int mid=(node.left+node.right)>>1; if(d<=mid) update(id<<1,d); else update(id<<1|1,d); pushup(id); } ll query(int id,int k){//查出當前線段樹中代價前k小的桌腿的代價總和 if(node.left==node.right){ return 1LL*node.left*k; } int mid=(node.left+node.right)>>1; if(lson.num==k) return lson.sum; else if(lson.num<k) return lson.sum+query(id<<1|1,k-lson.num); else return query(id<<1,k); } int main(){ scanf("%d",&n); for(int i=1;i<=n;++i){ scanf("%d",&a[i]); maxa=max(maxa,a[i]); ++c[a[i]]; } for(int i=1;i<=n;++i){ scanf("%d",&b[i]); maxb=max(maxb,b[i]); s[a[i]]+=b[i]; g[a[i]].push_back(b[i]); } for(int i=1;i<=maxa;++i){ c[i]+=c[i-1]; s[i]+=s[i-1]; } build(1,1,maxb); ll ans=inf; for(int i=1;i<=maxa;++i){//列舉所有長度,計算答案,取最小值 ll tmp=s[maxa]-s[i]; if(2*g[i].size()>c[i]){//數目足夠多,不用刪比它小的 ans=min(ans,tmp); } else{//需要刪k個 int k=c[i]-2*g[i].size()+1; ans=min(ans,tmp+query(1,k)); } for(int j=0;j<g[i].size();++j){//將當前長度的桌腿加入線段樹 update(1,g[i][j]); } } printf("%lld\n",ans); return 0; }