日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Governing sand(权值线段树/主席树)

發布時間:2023/12/15 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Governing sand(权值线段树/主席树) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

鏈接:https://ac.nowcoder.com/acm/contest/887/C
來源:牛客網

時間限制:C/C++ 3秒,其他語言6秒
空間限制:C/C++ 65536K,其他語言131072K
64bit IO Format: %lld
題目描述
The Wow village is often hit by wind and sand,the sandstorm seriously hindered the economic development of the Wow village.
There is a forest in front of the Wowo village, this forest can prevent the invasion of wind and sand. But there is a rule that the number of tallest trees in the forest should be more than half of all trees, so that it can prevent the invasion of wind and sand. Cutting down a tree need to cost a certain amount of money. Different kinds of trees cost different amounts of money. Wow village is also poor.
There are n kinds of trees. The number of i-th kind of trees is P_iP i , the height of i-th kind of trees is H_iHi , the cost of cutting down one i-th kind of trees is C_iC i .(Note: “cutting down a tree” means removing the tree from the forest, you can not cut the tree into another height.)

輸入描述:
The problem is multiple inputs (no more than 30 groups).
For each test case.
The first line contines one positive integers n (1 \leq n \leq 10^5)n(1≤n≤10 5 ),the kinds of trees.
Then followed n lines with each line three integers H_i (1 \leq H_i \leq 10^9)H i (1≤H i ≤10 9 )-the height of each tree, C_i (1 \leq C_i \leq 200)C i (1≤C i ≤200)-the cost of cutting down each tree, and P_i(1 \leq P_i\leq 10^9)P i(1≤P i≤10 9 )-the number of the tree.
輸出描述:
For each test case, you should output the minimum cost.
示例1
輸入
復制
2
5 1 1
1 10 1
2
5 1 2
3 2 3
輸出
復制
1
2

題意:n種樹,每種樹有一個高度,砍掉需要的價值,以及數量。
現在我們要把最高的樹的數目嚴格大于所有樹數目的一半。問所需要的最小價值是多少。
一開始以為是貪心,后來又想是dp。最后想的主席樹。。。
用主席樹還是權值線段樹都行,因為我們求的是1~i區間的。
(主席樹做法)我們先把高度由小到大排個序之后,建立各個版本的主席樹,我們就從高到低去遍歷所有種類的樹。假如當前的樹的高度是H,那么所有大于H的樹都應該被砍掉。除此之外,假如最高的樹的數目不嚴格大于一半,那么我們應該去砍小于H的樹木,并且使這個值最小。這個就交給主席樹去做,我們在主席樹中已經統計出來了樹的數目,以及需要的花費。就可以統計出砍k顆樹所需要的最小價值。
主席樹代碼如下:

#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #define ll long long using namespace std;const int maxx=2e5+100; struct Node{ll h;ll v;ll num;bool operator <(const Node &a)const{return a.h>h;} }t[maxx]; struct node{ll l;ll r;ll sum;ll num; }p[maxx*40]; ll v[maxx]; ll root[maxx]; int n;ll numm;ll update(ll rot,ll l,ll r,ll pos,ll num) {ll cur=++numm;p[cur]=p[rot];p[cur].num+=(ll)num;p[cur].sum+=(ll)pos*(ll)num;if(l==r) return cur;ll mid=l+r>>1;if(pos<=mid) p[cur].l=update(p[rot].l,l,mid,pos,num);else p[cur].r=update(p[rot].r,mid+1,r,pos,num);return cur; } ll query(ll rot,ll l,ll r,ll num)//砍掉num棵樹 {if(l==r) return (ll)l*(ll)num;//如果到達了葉子節點,就砍掉num棵葉子節點。ll ans=p[p[rot].l].num;ll mid=l+r>>1;if(num<=ans) return query(p[rot].l,l,mid,num);//如果小于左子樹的樹數目else{return p[p[rot].l].sum+query(p[rot].r,mid+1,r,num-ans);//左子樹的數目不夠,就把左子樹的全都砍掉,剩下的去砍右子樹} }int main() {int tt;while(scanf("%d",&n)!=EOF){memset(v,0,sizeof(v));numm=0;for(int i=1;i<=n;i++) scanf("%lld%lld%lld",&t[i].h,&t[i].v,&t[i].num);sort(t+1,t+1+n);for(int i=1;i<=n;i++) v[i]+=v[i-1]+t[i].num;for(int i=1;i<=n;i++){root[i]=update(root[i-1],1,210,t[i].v,t[i].num);//各個版本的主席樹}ll Max=1e18;ll tempnum=0;ll sum=0;ll money=0;for(int i=n;i>=1;i--){tempnum=0;while(t[i].h==t[i-1].h)//如果有高度相同的樹,就一起加上,因為原題只說是高度一樣的樹,沒有說非得是種類相同的樹{tempnum+=t[i].v*t[i].num;sum+=t[i].num;i--;}sum+=t[i].num;tempnum+=t[i].v*t[i].num;ll temp=0;if(v[i-1]>=sum) temp=money+query(root[i-1],1,210,v[i-1]-sum+1);//至少要砍這些樹才能符合題意else temp=money;Max=min(Max,temp);money+=tempnum;sum=0;}printf("%lld\n",Max);} }

權值線段樹做法。
我承認權值線段樹的做法做麻煩了。。因為我是按著主席樹的思想做下去的。
我一開始把所有的信息都插入到了線段樹里。但是線段樹不像主席樹那樣有多個版本。所以統計完一棵樹之前就要把它刪掉。一開始沒有這樣做,wa成狗。0.00%的絕望。
代碼如下:

#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<vector> #define ll long long using namespace std;const int maxx=2e5+100; struct Node{ll h;ll v;ll num;bool operator<(const Node &a)const{return a.h>h;} }t[maxx]; struct node{ll l;ll r;ll sum;ll num; }p[maxx<<2]; ll v[maxx]; int n;void pushup(int cur) {p[cur].sum=p[cur<<1].sum+p[cur<<1|1].sum;p[cur].num=p[cur<<1].num+p[cur<<1|1].num; } void build(ll l,ll r,int cur) {p[cur].l=l;p[cur].r=r;p[cur].num=p[cur].sum=0;if(l==r) return ;ll mid=l+r>>1;build(l,mid,cur<<1);build(mid+1,r,cur<<1|1);pushup(cur); } void update(ll l,ll r,ll pos,ll num,int cur,int flag)//flag==0時代表著是刪除,flag==1時代表著添加。 {if(l==r){if(flag){p[cur].num+=num;p[cur].sum+=1LL*(l*num);}else{p[cur].num-=num;p[cur].sum-=1LL*num*l;}return ; }int mid=l+r>>1;if(pos<=mid) update(l,mid,pos,num,cur<<1,flag);else update(mid+1,r,pos,num,cur<<1|1,flag);pushup(cur); } ll query(ll l,ll r,int cur,ll num)//意思類似于主席樹的操作。 {if(num<=0) return 0;if(l==r) return (ll)num*(ll)l;ll mid=l+r>>1;ll ant=p[cur<<1].num;if(num<=ant) return query(l,mid,cur<<1,num);else return p[cur<<1].sum+query(mid+1,r,cur<<1|1,num-ant); } int main() {while(scanf("%d",&n)!=EOF){memset(v,0,sizeof(v));for(int i=1;i<=n;i++) scanf("%lld%lld%lld",&t[i].h,&t[i].v,&t[i].num);sort(t+1,t+1+n);build(1,210,1);for(int i=1;i<=n;i++) {v[i]+=v[i-1]+t[i].num;update(1LL,210LL,t[i].v,t[i].num,1,1);//一開始把所有的節點信息都加進去了,因為我是從n到1遍歷的。}ll Max=1e18;ll Money=0;ll sum=0;for(int i=n;i>=1;i--){ll cmoney=0;while(t[i].h==t[i-1].h){cmoney+=t[i].num*t[i].v;sum+=t[i].num;update(1LL,210LL,t[i].v,t[i].num,1,0);i--; }cmoney+=t[i].num*t[i].v;sum+=t[i].num;update(1LL,210LL,t[i].v,t[i].num,1,0);//在統計之前就要把它給刪除掉,因為不刪除有可能在刪比它高度小的樹的時候出現錯誤。。因為高度比它小,價值不一定比它小。那么就算小了,就不對了。剩下的和主席樹大同小異,權值線段樹就是主席樹的前身嘛!!ll temp=0;if(v[i-1]>=sum) temp=Money+query(1,210,1,v[i-1]-sum+1);else temp=Money;Max=min(Max,temp); Money+=cmoney;sum=0;}printf("%lld\n",Max);}return 0; }

還是太菜了,要理解一會兒才能徹底明白。。
努力加油a啊,(o)/~

總結

以上是生活随笔為你收集整理的Governing sand(权值线段树/主席树)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。