【BZOJ4548】小奇的糖果
阿新 • • 發佈:2018-11-06
「題目背景」
小奇不小心讓糖果散落到了地上,它對著滿地的彩色糖果胡思亂想。
「問題描述」
有 N 個彩色糖果在平面上。小奇想在平面上取一條水平的線段,並拾起它上方或下方的所有糖果。求出最多能夠拾起多少糖果,使得獲得的糖果並不包含所有的顏色。
「輸入格式」
包含多組測試資料,第一行輸入一個正整數 T 表示測試資料組數。
接下來 T 組測試資料,對於每組測試資料,第一行輸入兩個正整數 N、K,分別表示點數和顏色數。
接下來 N 行,每行描述一個點,前兩個數 x, y (|x|, |y| ≤ 2^30 – 1) 描述點的位置,最後一個數 z (1 ≤ z ≤ k) 描述點的顏色。
「輸出格式」
對於每組資料在一行內輸出一個非負整數 ans,表示答案。
「樣例輸入」
1
10 3
1 2 3
2 1 1
2 4 2
3 5 3
4 4 2
5 1 2
6 3 1
6 7 1
7 2 3
9 4 2
「樣例輸出」
5
「資料範圍」
對於 30% 的資料,N ≤ 100;
對於 60% 的資料,N ≤ 5000;
對於 100% 的資料,N ≤ 100000,K ≤ 100000,T ≤ 3。
第N道小奇系列的題目了(之前好像也做過一道小奇的糖果來著,不過那是IOI改編,有點難 )
模擬考的時候寫了暴力居然沒有分(!)
下面是自己寫的題解:
- 這是在糖果是撒在二維平面裡的,所以我們可以通過其中一維的座標離散化,然後通過列舉,轉成單一一維裡的問題。
- 把橫座標離散化掉,按橫座標從左到右,把橫座標相鄰的糖果用雙向的連結串列串在一起(對於有不同顏色的序列,這樣的操作很常見哦,記下來記下來)。
- 所以每一次在兩個相同顏色的糖果之間數一下其它糖果的數量,就可以來更新ans了,可以用樹狀陣列來維護區間裡的糖果數量。
- 然後想象一條掃描線,從下到上掃一遍,每一次把掃描線上的點遮蔽掉,再更新一次答案,這樣就可以完成對於水平線上糖果的更新了。
- 那水平線下的怎麼更新呢?一樣的嘛,為了減少程式設計複雜度,我們把縱座標取相反數,用一樣的辦法再做一次就可以了。
程式碼~
1 #include<iostream> 2 #include<cstdio> 3 #include<cstdlib> 4 #include<cstring> 5 #include<algorithm> 6 7 #define For(i,a,b) for(register int i=a;i<=b;++i) 8 #define Re register 9 #define Pn putchar('\n') 10 using namespace std; 11 const int N=1e5+10; 12 int Lc[N],Rc[N],lst[N]; 13 int X[N],sX[N]; 14 struct Point{ 15 int x,y,cl,id; 16 }pt[N]; 17 int c[N],n,m,x,y,Kx,ans=0; 18 19 inline void read(int &v){ 20 v=0; bool fg=0; 21 char c=getchar(); if(c=='-')fg=1; 22 while(c<'0'||c>'9'){c=getchar(); if(c=='-')fg=1;} 23 while(c>='0'&&c<='9'){v=v*10+c-'0',c=getchar(); if(c=='-')fg=1;} 24 if(fg)v=-v; 25 } 26 void write(int x){ 27 if(x>9)write(x/10); 28 int xx=x%10; 29 putchar(xx+'0'); 30 } 31 bool cmpX(const Point &a,const Point &b){ 32 return a.x<b.x; 33 } 34 bool cmpY(const Point &a,const Point &b){ 35 return a.y<b.y; 36 } 37 38 39 int LB(int x){ 40 return x&(-x); 41 } 42 void upD(int k,int dt){ 43 for(Re int i=k;i<=n;i+=LB(i)){ 44 c[i]+=dt; 45 } 46 } 47 int Qry(int k){ 48 int ans=0; 49 for(Re int i=k;i>=1;i-=LB(i)){ 50 ans+=c[i]; 51 } 52 return ans; 53 } 54 55 void makeA(int lx,int rx){ 56 if(lx>rx)return; 57 int tp=Qry(rx)-Qry(lx-1); 58 ans=max(tp,ans); 59 } 60 void PickupCandy(){ 61 62 X[0]=0; X[n+1]=n+1; 63 memset(lst,0,sizeof(lst)); 64 memset(c,0,sizeof(c)); 65 66 sort(pt+1,pt+n+1,cmpX); 67 68 For(i,1,n){ 69 upD(pt[i].x,1); 70 } 71 72 For(i,1,n){ 73 int ID=pt[i].id; 74 int prC=lst[pt[i].cl]; 75 Lc[ID]=prC; Rc[ID]=n+1; 76 if(prC) Rc[prC]=ID; 77 makeA(X[prC]+1,X[ID]-1); 78 lst[pt[i].cl]=ID; 79 } 80 For(i,1,Kx){ 81 makeA(X[lst[i]]+1,X[n+1]); 82 } 83 84 sort(pt+1,pt+n+1,cmpY); 85 86 int Px=1; 87 For(i,1,n){ 88 while(Px<=n&&pt[i].y==pt[Px].y){ 89 upD(X[pt[Px].id],-1); 90 Px++; 91 } 92 int ID=pt[i].id; 93 Lc[Rc[ID]]=Lc[ID]; Rc[Lc[ID]]=Rc[ID]; 94 makeA(X[Lc[ID]]+1,X[Rc[ID]]-1); 95 } 96 return; 97 } 98 99 int main(){ 100 //freopen("candy.in","r",stdin); 101 //freopen("candy.out","w",stdout); 102 int T; read(T); 103 while(T--){ 104 read(n); read(Kx); 105 ans=0; 106 For(i,1,n){ 107 read(pt[i].x); read(pt[i].y); read(pt[i].cl); 108 pt[i].id=i; 109 sX[i]=pt[i].x; 110 } 111 sort(sX+1,sX+n+1); 112 For(i,1,n){ 113 X[i]=lower_bound(sX+1,sX+n+1,pt[i].x)-sX; 114 pt[i].x=X[i]; 115 } 116 PickupCandy(); 117 For(i,1,n)pt[i].y*=-1; 118 PickupCandy(); 119 write(ans); Pn; 120 } 121 // fclose(stdin); fclose(stdout); 122 return 0; 123 }