P6829 IOI2020 植物比較

2022-04-07 20:39:49 字數 3220 閱讀 3911

p6829 [ioi2020]植物比較

聽wc2021的時候聽到了這道題,然後就來做了。

大概思路就是處理出乙個類似拓撲序的東西。如果乙個數後面 \(k\) 個數中比它大的數都已經擴充套件過了,那麼就擴充套件它。

每次取出乙個 \(0\) 擴充套件,用線段樹區間減動態來維護每個數後面比它小的數的個數(有多個 \(0\) 取哪個並不那麼容易解決,後面會講)。

這樣可以保證下標差 \(的兩個數可以通過比較拓撲序大小來比較大小,即拓撲序小的更大。

所以,如果兩個數大小關係確定,那麼就比較拓撲序(後文寫作 \(tpn\))。否則返回 \(0\) 。

考慮如何判斷能否判定大小關係。

不妨 \(tpn_a,那麼從 \(a\) 開始,不斷往更大的 \(tpn\) 跳,同時維持大小的確定性,如果能跳到 \(b\) ,那麼就可以判定大小關係。

維持大小確定性只需要不斷往下標差 \(的區域跳即可。

可以處理出每個數往左 \(k\) 個數中 \(tpn\) 最小的比 \(a\) 拓撲序大的點,跳到不能跳為止,顯然倍增優化一下。往右也要擴充套件一次。

這個可以按照 \(tpn\) 從大到小加入位置,用線段樹維護區間最小值解決。

如果兩次至少有一次區域包含了 \(b\) 那麼就可以確定大小關係。

然而在實現的時候我遇上的最大的問題是在預處理拓撲序。

如果出現多個 \(0\) ,該取哪個?

直接取下標最小的必然是錯的。

考慮如下資料: \(\rm\) 。

一開始應該找的拓撲序最小的點不應該是 \(2\) 。因為 \(r_5\) 後面三個數,也就是 \([r_5,r_1,r_2]\) ,沒有大於 \(r_5\) 的,說明 \(r_1。

同理,如果找 \(5\) ,發現 \(r_4\) 後面三個數中間沒有大於 \(r_4\) 的,所以 \(r_4>r_5\) 。

問題應該很明確了:先找到乙個 \(0\) ,如果它左邊 \(k\) 個之內有 \(0\),那麼優先取左邊的那個。

剩下就全是實現的問題了。

考慮多開一顆線段樹維護所有 \(0\) 的位置,對於每乙個區間維護:最靠左的 \(0\) ,最靠右的 \(0\) ,區間相鄰的 \(0\) 的最大距離。

同時在原來維護區間減的線段樹維護區間最靠前的 \(0\) 的位置,區間最小值。

處理的拓撲序的時候,先在原來的線段樹查詢出最靠左的 \(0\) 的位置。

如果它可以擴充套件到 \(n\) (從環的另一端繞),那麼再在第二顆線段樹上二分端點最靠左的合法字尾,這樣子就能找到我們需要的位置了!

複雜度 \(o(n\log n)\) 。提交記錄

#include"plants.h"

#includeusing namespace std;

#define fi first

#define se second

#define pb push_back

#define mkp make_pair

#define sz(v) (int)(v).size()

templateinline bool ckmax(t&x,t y)

#define rep(i,x,y) for(int i=x,i##end=y;i<=i##end;++i)

#define per(i,x,y) for(int i=x,i##end=y;i>=i##end;--i)

typedef long long ll;

const int n=200005;

const int t=n<<2;

const int inf=0x3f3f3f3f;

int n,a[n],tpn[n],tpo,len;

int l[20][n],r[20][n];

ll dl[20][n],dr[20][n];

vectorv0;

namespace sg1

void build(int l,int r,int p,int*a)

void pushdown(int p)

}void get0(int p,int l,int r)

void update(int ql,int qr,int d,int l=1,int r=n,int p=1)

pushdown(p);

int mid=(l+r)>>1;

if(ql<=mid)update(ql,qr,d,l,mid,lc);

if(mid>1;

if(pos<=mid)change(pos,d,l,mid,lc);

else change(pos,d,mid+1,r,rc);

pushup(p);

}pairquery(int ql,int qr,int l=1,int r=n,int p=1)

int query(int l=1,int r=n,int p=1)

inline bool cmp(const int&a,const int&b)

void init(int k,std::vectorr)

tpn[x]=++tpo;

sg1::change(x,inf),sg2::change(x,0);

v0.clear();

sg1::update(max(1,x-k+1),x,-1);

if(x-k+1<1)sg1::update(n+x-k+1,n,-1);

for(int j:v0)sg2::change(j,1);

} for(int i=1;i<=n;++i)a[i]=inf;

sg1::build(1,n,1,a);

for(int i=1;i<=n;++i)a[i]=i;

sort(a+1,a+n+1,cmp);

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

pairtr=sg1::query(x,min(x+k-1,n));

if(tr.fin)

sg1::change(x,tpn[x]);

l[0][x]=le,r[0][x]=ri;

dl[0][x]=dis(le,x),dr[0][x]=dis(x,ri);

} for(int i=1;i<=19;++i)

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

l[i][j]=l[i-1][l[i-1][j]],r[i][j]=r[i-1][r[i-1][j]],

dl[i][j]=dl[i-1][j]+dl[i-1][l[i-1][j]],

dr[i][j]=dr[i-1][j]+dr[i-1][r[i-1][j]];

}

題解P3354 IOI2005 Riv 河流

p3354 ioi2005 riv 河流 這是一道比較好的樹型dp,在參考了網上的一些題解後,蒟蒻終於把它給做了出來 可以看到這道題如果只用二維表示狀態明顯是不夠的 所以設狀態 f 表示 i 為根節點,j 為它的乙個建有伐木場的父節點,k 為 i 與它的子樹共建的伐木場的數量 考慮再開乙個陣列 g ...

認識P2P,利用P2P

是peer to peer的縮寫 好象還看到過文章說是point to point,我也不清楚,網上的資料也不清楚,鬱悶 peer在英語裡有 地位 能力等 同等者 同事 和 夥伴 等意義。這樣一來,p2p也就可以理解為 夥伴對夥伴 的意思,或稱為對等聯網。目前人們認為其在加強網路上人的交流 檔案交換...

P2P網路模型

1 靜態配置模型 靜態配置模型是一種相對靜態而簡單的對等點定位模型。在該模型中,每個對等點都確切地知道存在於其p2p 網路中其它對等點的位置以及它們所提供的共享資源內容。缺點 網路無法應付不能預知的隨機事件和臨時變更,比如對等點隨機進入和退出網路。優點 整個網路在外部攻擊面前表現得很穩固。2 動態配...