\[\large\texttt
\]hydrooj 每日將從 hydrooj 主題庫及各大域中選出一題附以詳解在此處分享給各位使用者。
[coci2018-2019 final t4] tenis
vito 十分喜歡打網球。不久,他就會組織一次大規模的錦標賽。這次錦標賽會有 \(n\) 名選手參加,編號為從 \(1\) 到 \(n\)。vito 在過去幾年跟蹤了這些選手的資料。因此,他確定了這些選手在三種不同的球場:紅土,草地和硬地上比賽的能力值。也就是說,對於每種場地,他都按最強到最弱的順序確定了選手的排名。
vito 的錦標賽賽制有點與眾不同。一共會進行 \(n-1\) 輪比賽。在每場比賽中,還沒有被淘汰的兩名選手會在某種特定的場地上進行比賽。在這種場地上較弱的選手會被淘汰出局。\(n-1\) 輪比賽後唯一的勝者就是這次錦標賽的冠軍。
vito 是乙個很有影響力的人,可以操縱比賽的結果。即對於每場比賽,vito 可以選擇參賽選手和比賽場地。當然,他只能選擇未被淘汰的選手。
vito 經常更新他收集的資料,他有時會交換在某種場地上兩名選手的排名。並且他有很多朋友,有些朋友會問他:「選手 \(x\) 是我的外甥,他有機會奪冠嗎?」,為了回答這些詢問,你需要寫乙個程式幫助 vito 更新排名,並根據當前時刻 vito 的排名表回答他朋友的提問。
思維題。
拿到題目首先觀察樣例。
4 4
1 2 3 4
2 1 3 4
2 4 3 1
1 11 4
2 3 1 4
1 4
針對第二個事件,我們發現,雖然在前兩個場地 \(4\) 都是最弱的,但是在第三個場地 \(4\) 能打贏 \(1\) 和 \(3\),而在第乙個場地 \(1\) 又能打贏 \(2\)。因此只需讓能被選手 \(4\) 打敗的人先去打選手 \(4\) 打不過的人,選手 \(4\) 才有可能獲得勝利。
將以上策略抽象成圖,將每乙個人視為乙個結點,向每個他能打敗的人(不管在哪個場地)都連一條邊,那麼詢問就是看從這個人的結點出發,能否遍歷其他所有結點。如下圖:
(此處 \(1.1,1.2,1.3\) 為選手 \(1\) 在三個場地的排名,在這種方法中可縮為乙個點)
這時處理詢問的複雜度為 \(\mathcal(n)\),總時間複雜度為 \(\mathcal(n\times q)\),期望得分 \(30\) 分。
我們發現問題的瓶頸在於處理詢問,而上述處理方法基於連向其他結點的邊。為方便觀察,先將這些邊刪去。我們來隨手搓一組。
5 0
1 2 4 3 5
2 1 4 5 3
1 4 2 3 5
將同乙個選手在三個場地的位置用邊連線,如下圖:
此時選手 \(1\)、選手 \(2\)、選手 \(4\) 可能獲勝。
可以發現,能獲勝的選手和不能獲勝的選手中間有一道明顯的分隔線。這條分割線滿足:沒有一條邊橫跨分割線。這時在分割線左邊的選手能獲勝,右邊的則不能。
然而隨手一組就 hack 掉了。比如:
5 0
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
在這組中有多條滿足要求的分割線,怎麼辦?顯然只有最左邊的是正確的。考慮維護最左邊的分割線。
為什麼這樣是正確的?考慮分割線左邊選手的情況。顯然左邊的選手可以直接或間接打敗在左邊的其他選手。假設某乙個選手不能打敗左邊的其他選手,那麼這條分割線一定可以向左移動,把這個選手排除在外。那麼這樣就不滿足最左邊的分割線這一前提條件。因此假設不成立。
基於以上事實,分割線左邊的選手必定可以直接或間接打敗其他選手。同樣的,分割線右邊的選手不可能直接或間接打敗左邊的全部選手。(同樣可以反證)
這條線如何維護呢?我們記陣列 \(p\),\(p_i\) 表示有 \(p_i\) 個選手的邊沒有跨過 \(i\)。記第 \(i\) 位選手的在第 \(j\) 個場地的排名為 \(d_(1\le j\le 3)\),那麼對於這名選手來說,他的邊不會跨過 \(\max(d_)\to n~(1\le j\le 3)\),體現在 \(p\) 陣列上即對 \(p_i \to p_n\) 區間加 \(1\)。
最後,\(p\) 何時滿足條件?根據 \(p_i\) 的定義可知,若 \(p_i=i\),則此處有一條分割線。找最左邊的一條即可。
總結上文,需要支援的操作有:
用線段樹維護即可。時間複雜度 \(\mathcal(q \log n)\)。
tips:線段樹葉節點可以賦初值 \(-l\),其中 \(l\) 為結點代表的範圍。在每個結點裡記最大值。查詢時樹上二分,若左子樹最大值為 \(0\),查左子樹,否則查右子樹。
#include#define ll long long
#define reg register
#define _max(a,b) ((a)>(b)?(a):(b))
#define max(x,y,z) ((x)>(y)?_max((x),(z)):_max((y),(z)))
#define _max(x) max(d[1][x],d[2][x],d[3][x])
#define f(i,a,b) for(reg int i=(a);i<=(b);++i)
using namespace std;
bool beginning;
inline int read();
const int n=1e5+5;
int n,q,d[4][n],ans;
struct p f[n<<2];
#define ls (x<<1)
#define rs (x<<1|1)
void build(int x,int l,int r)
int mid=l+r>>1;
build(ls,l,mid);
build(rs,mid+1,r);
f[x].mx=_max(f[ls].mx,f[rs].mx);
}inline void push_down(int x)
void modify(int x,int l,int r,int val)
push_down(x);
int mid=f[x].l+f[x].r>>1;
if(l<=mid)modify(ls,l,r,val);
if(r>mid)modify(rs,l,r,val);
f[x].mx=_max(f[ls].mx,f[rs].mx);
}int query(int x,int l,int r)
bool ending;
int main() else if(op==2)
} return 0;
}inline int read()
每日一題 1
題目詳情 peter喜歡玩數字遊戲,但數獨這樣的遊戲對他來說太簡單了,於是他準備玩乙個難的遊戲。遊戲規則是在乙個n n的 裡填數,規則 對於每個輸入的n,從左上角開始,總是以對角線為起點,先橫著填,再豎著填。這裡給了一些樣例,請在樣例中找到規律並把這個n n的 列印出來吧。輸入描述 多組測試資料 資...
每日一題2018 3 21
leetcode 2 模擬十進位制運算考察單鏈表基本操作。題無難點,個人基礎需要提高。definition for singly linked list.struct listnode class solution while p while q if shi val s next null ret...
每日一題2018 3 22
leetcode 03 最長不重複子串 第一反應就是動態規劃。看到了網上的方法一。直接把問題簡化為找兩個重複字元間的最長距離,太巧妙了!class solution if i idx max locs s i i return max ling老師的方法二 仍舊轉化為動態規劃,但是為節省空間不再開個...