省選模擬3 9

2022-10-08 18:30:09 字數 3756 閱讀 2188

看給出的部分分,給出的縱座標都相同

於是從所有魚頭胖往每個牆的兩個端點分別引一條線

覆蓋到胖頭魚所在的縱座標線,可以差分以下,左邊的線 \(-1\) 右邊的 \(+1\)

可能會有重複覆蓋的情況

於是可以用類似括號匹配的方法對每個魚頭胖引出的線進行處理

可以擴充套件這個做法,只需要將所有線都存到牆的端點裡,再按照極角序排序

然後再跟胖頭魚的連線比較二分一下,就能知道要減或者加多少個 \(1\) 了

可以用叉積來進行極角序排序

code

#include//#define int long long//overflow !!! memory limit !!!

#define rint signed

#define inf 0x3f3f3f3f3f3f3f3f

using namespace std;

inline int read()

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

return x*f;

}int n,k,m,op;

int x[100010],y[100010];

int l[60],r[60],h[60];

struct data};

struct dddd};

vectorvec[110];

vectorv;

signed main());

v.emplace_back((dddd));

} sort(v.begin(),v.end());

for(int j=0,l=0,r=0,k=0;j

正著新增乙個數,修改的位置均攤 \(o(n)\) 個,可以根據這個做,我不太會

於是考慮倒著刪除乙個數

那修改的區間肯定是他上一次出現的位置一直往前直到 \(mex = a_i\)

可以用線段樹上二分找到這個位置

那現在就要維護區間賦值和區間歷史值和

線段樹上每個節點維護兩個資訊,乙個是當前的 \(mex\) 乙個是 \(sum\)

\(sum\) 表示的就是以當前位置為左端點,右端點在現在列舉的位置到 \(n\) 的區間的 \(mex\) 值和

用類似掃瞄線的思路把詢問離線下來

拆成 \(l\) 和 \(r+1\) 分別詢問 \([l,r]\) 的值然後造成 \(+1,-1\) 的貢獻

具體維護,我用了 \(3\) 個標記

分別是 \(c,u,v\) 分別表示累加次數,賦值標記,在賦值標記後的累加貢獻

下傳時先 \(c\) 再 \(u\) , \(v\) 無所謂

下傳 \(c\) 時要先判斷左右兒子有沒有 \(u\) ,有的話就轉成 \(v\) 沒有就正常下傳

code#include#define int long long//overflow !!! memory limit !!!

#define rint signed

#define lson rt<<1

#define rson rt<<1|1

#define inf 0x3f3f3f3f3f3f3f3f

using namespace std;

inline int read()

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

return x*f;

}int n,q,blo;

int a[1000010],pre[1000010],lst[1000010];

bool vis[1000010];

int ans[1000010],mex[1000010];

int bl[1000010],v[1000010];

int l[1010],r[1010];

int sum[1010],vsum[1010],utag[1010],ctag[1010],vtag[1010],mx[1010];

struct data;

vectorvec[1000010];

struct segst[1000010*4];

inline void pushup(int rt)

inline void pushdown(int rt,int l,int r)

if(st[rt].utag!=-1)

if(st[rt].vtag)

}void build(int rt,int l,int r)

void upd(int rt,int l,int r,int l,int r,int k)

int query(int rt,int l,int r,int l,int r)

int getpos(int rt,int l,int r,int k)

signed main()

for(int i=n,v=0;i;i--)

build(1,1,n);q=read();

for(int i=1,l,r;i<=q;i++));

vec[r+1].emplace_back((data));

} for(int i=n,l,r;i;i--)

if(st[1].utag!=-1) st[1].vtag+=st[1].utag,st[1].vsum+=st[1].utag*n;

else st[1].ctag++,st[1].vsum+=st[1].sum;

} for(int i=1;i<=q;i++) printf("%lld\n",ans[i]);

return 0;

}

轉化一下,就是求本質不同子串個數,一般用 \(sa\) 或者 \(sam\)

由於最小表示法,所以用 \(sa\) 來求

比較時,先二分求出 \(lcp\) 再比較下一位的值

將字串的雜湊定義為每個字元與他前乙個相同的字元相差的距離

用主席樹存下每乙個字尾的雜湊值

排完序後直接求本質不同子串個數

code#include//#define int long long//overflow !!! memory limit !!!

#define rint signed

#define cmin(x,y) ((x)<(y))?(x):(y)

#define uint unsigned long long

#define inf 0x3f3f3f3f3f3f3f3f

using namespace std;

inline int read()

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

return x*f;

}int n,ans;

int a[50010],t[50010];

int rt[50010],lst[50010],tot;

int pre[50010],nxt[50010],v[50010];

uint pw[50010];

struct segst[50010*20];

inline void pushup(int x,int l,int r)

void build(int &x,int l,int r)

void upd(int &x,int l,int r,int pos,uint k)

uint query(int x,int l,int r,int l,int r)

inline int getlcp(int x,int y)

return res;

}inline int s(int x,int k)

inline bool cmp(int x,int y)

if(res==min(lenx,leny)) return lenx

省選模擬 19 09 11

ps.博主趁資訊課摸魚考的暴零模擬 看門人憑感覺就知道是長鏈剖分,將路徑查分一下,dis u di sv 2 dis lc adis u dis v 2 dis disu disv 2 disl ca 維護fu,if fu,i 表示u的子樹,深度為 i 的點的 dis disdi s最大值 考慮如何...

省選模擬96

容易發現當 k 3 時無解。然後容易證明當 k 3 時,只有 m 3 才是有解的。然後直接做不好做,考慮欽定然後容斥出合法方案。對於 k 3 列舉乙個點,然後計算另乙個的方案數。其他情況類似,欽定滿足條件的角,然後容斥。然後對於每乙個 o n 的式子用組合恒等式大力化簡就可以做到 o 1 了。考慮每...

省選模擬86

首先考慮基礎的dp定義,那麼發現轉移需要的係數只和dp是奇數的點的個數有關,所以將這個東西記錄在dp狀態中就行了。然後推一下dp轉移,發現轉移係數和奇數的點的個數沒有關係,只與是否存在這樣的點有關,所以用01來記錄就可以了。考慮用總方案減去不合法的方案,也就是1號點能到達的點和2號點能到達的點沒有交...