THUWC2022 某科學的動態仙人掌

2022-07-12 06:06:11 字數 3045 閱讀 1094

2月24日的模擬賽上的一道題

直接計數是肯定沒法計數的,考試的時候我當時在一直想能不能類似於區間合併,想了好久感覺根本不行,就不會了,聽完題解之後發現這道題十分的nb,lxlnb

居然整體沒法考慮,那就考慮一下每個點對他們的貢獻,如下邊這張圖

很醜的一張

這一坨就代表有乙個聯通塊,我考慮能不能把貢獻在他的最淺處統計,也就是把這個最淺的點當作乙個代表點(就是把他當作一棵有根樹,深度最小的位置統計答案)

那這個點就需要滿足乙個條件:\([l,r]\)之間沒有乙個點比他淺並且和他的距離不超過\(c\),因為這樣的話最淺的點就是那個點

但是這樣還有乙個問題,乙個連通塊可能會有多個滿足這個條件的點,這些點的深度相同,他們的距離小於等於\(c\),顯然這個條件的這些點是乙個集合,我需要考慮如何找到這個集合並且給這個集合對答案的貢獻去重

我先考慮那個條件咋處理,其實非常簡單,只需要想一下,比他淺而且距離小於\(c\)

令我現在的這個點為\(x\),那個點為\(y\),基本上就滿足乙個性質

c如果是奇數,一定滿足\(dis(y,fa(x,(c+1)/2))<=(c-1)/2\)

c如果是偶數,一定滿足\(dis(y,fa(x,c/2))<=c/2-1\ 或者\ dis(y,fa(x,c/2+1))<=c/2-1\)

如果沒有乙個點滿足上述條件,那麼就說明這個點是有資格當代表點的,當然有資格也是在特定的\(l,r\)的條件下滿足的,那麼究竟是哪些呢,你可以找到這些範圍裡面\(x\)的前驅和後繼,記為\(pre,suf\), \(x\)就在\((pre,suf)\)之間有資格,畫一畫就知道為啥了,因為如果包含了\(pre\)那麼這個\(pre\)比他淺而且距離小於\(c\)就不滿足之前的定義了

現在考慮前驅和後繼咋求,假如我現在要找的點是滿足\(dis(y,fa(x,c))<=d\)的\(y\)點,那其實和\(x\)關係不大,就相當於求距離\(fa\)小於\(d\)的乙個特殊點,樹上考慮距離,咋想?點分治呀,但經過剛才的轉換這現在是一棵有根樹,但沒事呀,我求的只是關於距離的東西,才不管這些

小補充:我要求的這個距離,直接當成無根樹沒問題還有乙個東西就是反正不管咋求,在那3個距離限制中求出來的東西都比\(x\)高,都能用

還有就是有可能我當前的這個點的深度小於d,我連\(fa(x,c)\)都沒有,我怎麼找?直接讓根當作他的那個父親嗎?不行,因為這樣找就有可能找到乙個比他深的點

如果讓根節點當作根

處理這個問題我的實現方法常數極大,給1加了\(c/2+1\)個父親,這樣就沒這個問題了

現在考慮樹分治的過程,其實就是個很常規的點分

我現在找乙個分治中心,先求出每個點到分治中心的距離,排個序,按照順序考慮插入set查詢前驅和後繼,如果他當前到分治中心的距離為\(dis\)的話,那麼等到距離小於\(d-dis\)的點全部插入完了,就查詢這個,可以拿個類似雙指標實現,查詢這個有乙個問題就是查詢這個點不是查詢他自己,而是查詢他的兒子的前驅和後繼,就這樣,遞迴下去就好了

我現在知道了那些點的影響範圍了,其實就是乙個矩形範圍(可以看lxl畫的圖),我現在的關鍵問題就是如果把深度相同的點去重,這乙個集合的點的乙個共性就是他們的c/2級祖先是相同的,那我就在這個祖先點考慮,還是根據lxl畫的圖,把矩形劃分一下,然後就是乙個掃瞄線求矩形和的模板了,就完了。

我的這個寫法是2log的寫法,不管了

**在下面

#include#define maxn 3000005

using namespace std;

inline int read()

while(ch>='0'&&ch<='9')

return x*f;

}int n,m,c,n;

int tot,head[maxn];

struct edge e[maxn<<1];

inline void add(int u,int v) ; head[u]=tot;

}int up[maxn][20],dep[maxn];

inline void dfs(int u)

int pre[maxn],suf[maxn],fa[maxn];

vectorkk[maxn];

struct dian_fen_zhi

inline int get_root(int u,int ff)

mx[u]=max(mx[u],s-siz[u]);

if(mx[u]<=s/2) rt=u;

return siz[u];

} int dis[maxn],sta[maxn],hi,ti;

setsets; //資料結構查詢前驅和後繼

set::iterator it;

inline void solve(int u)

}}

int now=ti;

sets.insert(0),sets.insert(n+1); //先插入一些點

dis[0]=1<<30; sta[++ti]=0;

for(int i=1;i<=ti;i++)

inline void get_ans()

for(int i=1;i<=m;i++) cout<

cout<

}int main()

for(int i=1;i<=n;i++) suf[i]=n+1; //初始話後繼陣列

up[n][0]=0; dfs(n); //處理倍增陣列,一會用來求祖先

if(c%2==0)

else t1.c=c/2+1,t1.d=c/2,t1.get_pre_suf();

//求出乙個集合的元素

for(int i=1;i<=n;i++)

bulit(); //建矩形

sort(seg+1,seg+seg_cc+1,cmp);

get_ans();

}

某科學的間斷超電磁炮

時間限制 1000 ms 記憶體限制 65535 k 問題描述 炮姐bilibili為了練習自己的能力,於是左右開弓開始shoot 開始的時候電磁炮應該是間斷的,所以打到的靶子也是不連續的。比如左手能打到1號 2號 3號靶子,右手能達到1 2 3 4 5號靶子。雖然她想知道自己到底打到了哪些靶子很容...

HAUT校賽 某科學的打麻將

時間限制 1 秒 記憶體限制 64 mb 提交 18 解決 2 提交狀態 題目描述 過年打麻將果然是一項必備技能 霧 打麻將的起手式是整理好自己手中的牌,現在你有十三張牌 只可能出現一萬到九萬,一筒到九筒,一條到九條 你要把這些牌整理好,使得相同花色的牌必須在連續的唯一一段 即所有的 萬 要放在一起...

BZOI1131 某科學的樹形DP

這個題目僅僅是因為我找了半天也沒找到這個神奇題目的名字而瞎起了乙個,題目過於簡單,題意過於明了,簡直像是某信奧書上講解樹形dp知識點用的模板。就這麼令人無語。給出乙個n個點的樹,找出乙個點來,以這個點為根的樹時,所有點的深度之和最大 input 給出乙個數字n,代表有n個點.n 1000000 下面...