2018 ICPC 徐州區域賽 H Rikka with A Long Colour Palette
阿新 • • 發佈:2018-12-14
題意:
給出n個數軸上的線段,進行每個線段染一種顏色,求混合有k種顏色的距離的和。
題解:
如果某一段被k條及以上線段覆蓋,那麼這一段一定是滿足條件的,問題是如何求解方案數。
確定一條線段染什麼顏色一定是根據左右端點判斷得到的,所以我們只關心端點。
將左端點記為1,右端點記為-1,排序,相同的位置,右端點更靠前。
用一個佇列儲存沒有染色的點,一開始所有顏色都在佇列。
從小到大列舉位置
如果是左端點,並且佇列不為空,我們就將這個線段染成隊首的顏色
如果是右端點,如果這條線段染過色,就將該顏色放入隊尾,進行回收
但是有幾個細節要考慮
左端點時,如果所有顏色都染了,該染什麼顏色?隨便染嗎?不是的,因為可能後面可能會用到,解決方法是將其將放入佇列(棧)中,留著以後再用
什麼時候用?
假如說處理完這個位置後,發現覆蓋的顏色不夠k種,這時我們就看之前存下來的線段,如果還沒有被染色,就取出來染色。
這樣就能利用起來所有的線段了
程式碼:
#include<bits/stdc++.h> #define N 200010 #define INF 0x3f3f3f3f #define eps 1e-10 #define pi 3.141592653589793 #define P 998244353 #define LL long long #define pb push_back #define cl clear #define si size #define lb lower_bound #define ub upper_bound #define mem(x) memset(x,0,sizeof x) #define sc(x) scanf("%d",&x) #define scc(x,y) scanf("%d%d",&x,&y) #define sccc(x,y,z) scanf("%d%d%d",&x,&y,&z) using namespace std; struct dd { int x,y,id; bool operator < (const dd d)const { return x==d.x?y<d.y:x<d.x; } }a[N<<1]; int col[N]; int main() { int T; sc(T); while(T--) { int n,m; scc(n,m); int cn=0; mem(col); for (int i=1;i<=n;i++) { int x,y; scc(x,y); a[++cn]=dd{x,1,i}; a[++cn]=dd{y,-1,i}; } sort(a+1,a+cn+1); queue<int> q; stack<int> st; for (int i=1;i<=m;i++) q.push(i); int t=0,k=1,prek=0,pret=0,ans=0; while(k<=cn) { int p=k; while(a[p].x==a[k].x) { if (a[p].y==-1) { int r=a[p].id; if (col[r]!=0) { t--; q.push(col[r]); }else col[r]=1; } if (a[p].y==1) { int r=a[p].id; if (t>=m) {st.push(r);} else { t++; col[r]=q.front(); q.pop(); } } p++; } while(t<m) { while(!st.empty() && col[st.top()]) st.pop(); if (st.empty()) break; t++; int r=st.top(); st.pop(); col[r]=q.front(); q.pop(); } if (pret>=m) ans+=(a[k].x-prek); pret=t; prek=a[k].x; k=p; } printf("%d\n%d",ans,col[1]); for (int i=2;i<=n;i++) printf(" %d",col[i]); puts(""); } }