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 動態配...