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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

Bzoj 4548: 小奇的糖果(双向链表+排序+树状数组)

發布時間:2023/12/18 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Bzoj 4548: 小奇的糖果(双向链表+排序+树状数组) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

以下內容來自ShallWe's Blog

題目

4548: 小奇的糖果

Description

\(N\)個彩色糖果在平面上。小奇想在平面上取一條水平的線段,并拾起它上方或下方的所有糖果。求出最多能夠拾起多少糖果,使得獲得的糖果并不包含所有的顏色。

Input

包含多組測試數據,第一行輸入一個正整數\(T\)表示測試數據組數。
接下來\(T\)組測試數據,對于每組測試數據,第一行輸入兩個正整數\(N\),\(K\),分別表示點數和顏色數。
接下來\(N\)行,每行描述一個點,前兩個數\(x\),\(y\)(\(|x|,|y|≤2^30-1\))描述點的位置,最后一個數\(z\)\((1≤z≤k)\)描述點的顏色。
對于\(100%\)的數據,\(N≤100000,K≤100000,T≤3\)

Output

對于每組數據在一行內輸出一個非負整數\(ans\),表示答案

解題報告

考場上光彩爆零->寫了一個很長很長的臭程序,先講一下考場上的思路:
很容易看出,可以把合法的線段造成的收益看做矩形內部節點數,矩形內部節點數很好求,所以就是要找出矩形.
矩形顯然有三類,一類是枚舉\(x\)相鄰的相同顏色\(star\),之間通天遁地的矩形,一類是下邊貼一個\(star\),兩邊各貼一個相同顏色的\(star\),上邊貼頂的矩形,第三類和第二類相似;
所以我就將問題轉化成求一個點兩端的比它高(低)的第一對點的橫坐標;
我現場是用單調棧來搞的,每一個顏色維護上方一個單調遞減的棧,每次彈棧就形成矩形,這樣每個點可以形成上下兩個矩形,加上第一類矩形,一共是\(3n\)個矩形;


上面那個方法難寫難調細節很多;學習了hzwer的姿勢,使用雙向鏈表實際上作用就是維護兩邊最近的相同顏色的點,考慮如果當前的點是該顏色點中最高的那么雙向鏈表所指的橫坐標就能確定矩形左右邊界,當這個矩形確定后,這個最高點會對兩側點造成干擾,刪掉就好。這樣下矩形就確定好了,上矩形將縱坐標上下翻轉就好了,
提一句:求矩形內部節點個數->掃描線+樹狀數組/樹套樹隨便做。

代碼

#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cstdlib> using namespace std; const int N=100001; struct poi{int x,y,color,id; poi(){}poi(int x,int y,int color,int id):x(x),y(y),color(color),id(id){} } point[N]; int T,n,k,ans; int l[N],r[N],bit[N],vec[N],pre[N],w[N]; inline void in(int &x){char ch=getchar(); int f=1; for (;ch<'0'||ch>'9';ch=getchar())if (ch=='-') f=-1; for (x=0;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-48; x=x*f; } inline void init(){ans=0; } bool cmpx(poi a,poi b){return a.x<b.x; } bool cmpy(poi a,poi b){return a.y<b.y; } inline void add(int x,int val){for (;x<=n+1;x+=x&-x)bit[x]+=val; } inline int query(int x,int tmp=0){for (;x;x-=x&-x)tmp+=bit[x]; return tmp; } inline void up(int l,int r){if (l>r) return;int tmp=query(r)-query(l-1); ans=max(tmp,ans); } void solve(){memset(bit,0,sizeof(bit));memset(pre,0,sizeof(pre)); w[0]=0,w[n+1]=n+1;sort(point+1,point+1+n,cmpx); for (int i=1;i<=n;i++) add(point[i].x,1); int y,x;for (int i=1;i<=n;i++){x=point[i].id,y=pre[point[i].color];l[x]=y,r[x]=n+1; if (y) r[y]=x; up(w[y]+1,w[x]-1); pre[point[i].color]=x;}for (int i=1;i<=k;i++){up(w[pre[i]]+1,n+1); }sort(point+1,point+1+n,cmpy); for (int i=1,j=1;i<=n;i++){x=point[i].id; while (j<=n&&point[j].y==point[i].y){add(point[j].x,-1);j++;}l[r[x]]=l[x],r[l[x]]=r[x];up(w[l[x]]+1,w[r[x]]-1); } } int main(){ // freopen("candy.in","r",stdin); // freopen("candy.out","w",stdout); in(T);int x,y,z;while (T--){init();in(n),in(k); for (int i=1;i<=n;i++){in(x),in(y),in(z); point[i]=poi(x,y,z,i);}for (int i=1;i<=n;i++) vec[i]=point[i].x; sort(vec+1,vec+1+n); for (int i=1;i<=n;i++){ point[i].x=lower_bound(vec+1,vec+1+n,point[i].x)-vec;w[i]=point[i].x;} solve(); for (int i=1;i<=n;i++)point[i].y=-point[i].y; solve(); printf("%d\n",ans); }return 0; }

雙倍經驗:3658: Jabberwocky

轉載于:https://www.cnblogs.com/ShallWe2000/p/5776598.html

創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

總結

以上是生活随笔為你收集整理的Bzoj 4548: 小奇的糖果(双向链表+排序+树状数组)的全部內容,希望文章能夠幫你解決所遇到的問題。

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