YNOI2016 這是我自己的發明

2022-05-22 21:57:10 字數 2893 閱讀 6633

看到這個標題立刻想到:、

「絕地科學家,八倍不屏息啊,八百里外把頭打啊...」

首先我們發現如果只考慮第二個操作,這棵樹就是假的,我們可以直接莫隊解決

如果考慮換根的話...可以把乙個操作換成小於等於9個操作就可以了

當然怎麼換,有一些非常噁心的分類討論

嚶嚶嚶ynoi 題是好題 但是要卡常 首先要fread & fwrite

然後需要wxh的莫隊寫法

然後要算一下分塊大小

sqrt(q_size) -> (n / sqrt(q_size))

40 -> 100

嚶嚶嚶

#include#define ll long long

using

namespace

std;

inline

char

nc()

inline

intread()

char pbuf[100000] , *pp =pbuf;

inline

void push(const

char

ch)inline

void write(long

long

x)const

int maxn = 100010

;int

n,m,rt;

intqx;

inta[maxn],vi[maxn];

intq_size;

int first[maxn],to[maxn << 1],nx[maxn << 1

],cnt;

inline

void add(int u,int

v)inline

void ins(int u,int

v)structq;

q(int _l,int _r,int _id,int _opt)

bool

operator

< (const q &b)const

return l

}}qs[maxn * 45

];int fa[maxn][23

],dep[maxn],ind[maxn],oud[maxn],reh[maxn],dfn;

inline

void dfs(int

x)oud[x] =dfn;

}ll ans[maxn * 5

];ll now;

intcnt_x[maxn],cnt_y[maxn];

inline

int go_anc(int x , int

y)int xpos[10],ypos[10],opt_x[10],opt_y[10

];int

main()

dfs(rt = 1

);

//return 0;

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

int y = read(),z;q_size++;

tx = ty = 0

;

if(x == rt) xpos[++tx] = n , opt_x[tx] = 1

;

else

if(ind[rt] < ind[x] || ind[rt] > oud[x]) xpos[++tx] = oud[x] , opt_x[tx] = 1 , xpos[++tx] = ind[x] - 1 , opt_x[tx] = -1

;

else z = go_anc(x , rt) , xpos[++tx] = n , opt_x[tx] = 1 , xpos[++tx] = oud[z] , opt_x[tx] = -1 , xpos[++tx] = ind[z] - 1 , opt_x[tx] = 1

;

if(y == rt) ypos[++ty] = n , opt_y[ty] = 1

;

else

if(ind[rt] < ind[y] || ind[rt] > oud[y]) ypos[++ty] = oud[y] , opt_y[ty] = 1 , ypos[++ty] = ind[y] - 1 , opt_y[ty] = -1

;

else z = go_anc(y , rt) , ypos[++ty] = n , opt_y[ty] = 1 , ypos[++ty] = oud[z] , opt_y[ty] = -1 , ypos[++ty] = ind[z] - 1 , opt_y[ty] = 1

;

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

for(int k=1;k<=ty;k++)

if(xpos[j] &&ypos[k])

qs[++qx] = q(xpos[j] , ypos[k] , q_size , opt_x[j] *opt_y[k]);

}int si = (int)(n /sqrt(qx));

for(int i=1;i<=qx;i++)qs[i].bl = (qs[i].l - 1) /si;

sort(qs + 1,qs + qx + 1

);

int l = 0,r = 0

;

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

while(r < qs[i].r)

while(l > qs[i].l)

while(r > qs[i].r)

ans[qs[i].id] += now *qs[i].opt;

}for(int i=1;i<=q_size;i++)write(ans[i]);

fwrite(pbuf ,

1 , pp -pbuf , stdout);

}

view code

Ynoi2016 這是我自己發明的

link 支援換根和給定兩個點,求子樹中滿足權值相同的方案數 換根操作和遙遠的國度一題類似,直接對應到 rm 序上處理即可 後面的問題和 texttt 類似 仍然使用子樹對應在 rm 序上是一段連續區間,然後容斥得到下式 sum get l 1 1,x times get l 2 1,x get r...

Ynoi2016 這是我自己的發明(莫隊)

話說這道題資料是不是都是鏈啊,我不手動擴棧就全 re 不過 a 了這題還是很爽的,通過昨晚到今天早上的奮鬥,終於肝出了這題 其實樓上說的也差不多了,就是把區間拆掉然後莫隊瞎搞 弱化版 bzoj snoi2017 乙個簡單的詢問 那我先講弱化版吧 可以發現 sum get l 1,r 1,x time...

Ynoi2016 鏡中的昆蟲

區間不用種類的數的個數。這個問題可以轉化為對每個點維護乙個 pre 詢問 l sim r 中,有多少個位置是在 0 sim l 1 之間的。這個問題可以用二維偏序做。然後對於區間賦值的操作,可以證明,如果我們找到所有有變化的位置並且把它改掉,它的總更改次數為 o n m 級別的。那具體實現可以用 s...