第一行包含乙個正整數testcase,表示當前測試資料的測試點編號。保證1≤testcase≤20。
第二行包含三個整數n,m,t,分別表示節點數、初始邊數、運算元。第三行包含n個非負整數表示 n個節點上的權值。
接下來 m行,每行包含兩個整數x和 y,表示初始的時候,點x和點y 之間有一條無向邊, 接下來 t行,每行描述乙個操作,格式為「q x y k」或者「l x y 」,其含義見題目描述部分。
對於每乙個第一類操作,輸出乙個非負整數表示答案。 1
8 4 8
1 1 2 2 3 3 4 4
4 71 8
2 42 1
q 8 7 3 q 3 5 1
q 10 0 0
l 5 4
l 3 2 l 0 7
q 9 2 5 q 6 1 6 2 2
142
如果這道題不帶新增邊的操作的話直接上主席樹就可以了,那麼現在加了邊,主席樹上樹的樸素做法已經行不通了,那麼考慮一下加了邊實際上就是把兩個聯通分量連成了乙個聯通分量,那麼我們就需要對兩個聯通分量所代表的主席樹進行合併,那麼為了保證時間複雜度,我們每次把size較小的聯通分量合併到size較大的聯通分量中去,並且把對應的主席樹進行合併。然後就是樸素的主席樹上樹了。
#include #include #include const int maxn = 100005;
int first[maxn],e=1,cnt,n,m,q,val[maxn],id[maxn],num,hash[maxn],sz;
int belong[maxn],fa[maxn][25],size[maxn],root[maxn],ans,deep[maxn];
bool vis[maxn];
templateinline _t read()
struct nodetree[20000005];
#define ls(x) tree[x].l
#define rs(x) tree[x].r
#define sum(x) tree[x].sum
struct edgea[maxn<<3];
void push(int u,int v)
void insert(int &o,int old,int l,int r,int x)
inline void swap(int &x,int &y)
inline void hash_init()
inline int ghash(int x)
void build(int &o,int l,int r)
void dfs(int u,int f,int be)
return;}
inline int lca(int x,int y)
int query(int u,int v,int k)
else
}return hash[l];}
int main()hash_init();
build(root[0],1,sz);
for(int i=1;i<=n;i++)if(!vis[i])dfs(i,0,++num),id[num]=i;
while(q--)
else}}
BZOJ3123 森林(主席樹,啟發式合併)
神tm題面是 首先,求樹鏈上第k大,請參看bzoj2588 count on a tree 這道題目於是增添了乙個動態的合併森林的操作 所以直接啟發式合併就可以啦 我第一次交直接t了 加了一堆rg就ac了。神奇的register include include include include inc...
BZOJ 3123 森林 主席樹啟發式合併
第一行包含乙個正整數testcase,表示當前測試資料的測試點編號。保證1 testcase 20。第二行包含三個整數n,m,t,分別表示節點數 初始邊數 運算元。第三行包含n個非負整數表示 n個節點上的權值。接下來 m行,每行包含兩個整數x和 y,表示初始的時候,點x和點y 之間有一條無向邊,接下...
bzoj 3123(主席樹 啟發式合併)
傳送門 題解 對點到根維護權值線段樹,每次連邊就進行啟發式合併 用size啟發 詢問就按區間第k大的方式詢問,此處不再贅述。吐槽三點 1.說好的多組資料其實只有一組,醉了。2.1e9的資料按理說是需要離散化的,但是離散化了反而要re 可能是個人原因 3.這個 片的int為啥是畸形的。include ...