hdu3710(樹鏈剖分計算lca)

2021-08-31 19:30:57 字數 3100 閱讀 4399

突然發現剖分樹可以在log(n)的時間裡求出lca,於是又刪了幾十行的**。

#include #include #include #include #include using namespace std;

const int n = 20005;

const int m = 100005;

const int qn = m;

const int inf = 0x7fffffff;

typedef int vtype;

typedef pairpii;

#define mkpii make_pairstruct ees[n<<1], *fir[n];

struct node

}nodes[n<<1];

struct seses[m<<1], lea[m<<1];

int n, en, qn, m;

vectorqlca[n];

vectornes[n];

int par[n], fa[n]; //par[i]為i的直接前驅, fa用於並查集;

int ln, cnt; //ln為鏈的數目,cnt為剖分樹中節點的數目

int leanum;

int sons[n], que[n], dep[n], id[n], st[n], ed[n], root[n], top[n], snum[n];

//sons[i]表示i為根的子樹的大小,dep[i]表示節點的i的深度,id[i]為i所在鏈的標號,st和ed記錄每條鏈的左右標號,root記錄每條鏈的根節點的下標

//top[i]為第i條鏈的頂部節點,snum[i]表示i的直接後繼的個數

int ith[n], pmin[n], seg[n]; //ith[i]表示節點i是其父節點的第ith[i]個兒子(按訪問順序),

//seg在鏈上構建線段樹的時候使用

vtype iw[n]; //iw[i]表示節點i在最小生成樹中與其他節點之間的邊的權值的總和

int tr; //最小生成樹的根節點

inline void add_e(int u, int v)

inline void newnode(int& id, int l, int r)

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

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

build(nodes[id].ls, l, mid);

build(nodes[id].rs, mid+1, r);

}void inittree()}}

//計算子樹大小

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

for(i = r-1; i >= 0; i--)

}//剖分鏈

l = r = 0;

que[r++] = tr;

ln = cnt = 0;

while(l != r)}}

if(best >= 0)}}

u = best;

}root[ln] = -1;

build(root[ln], st[ln], ed[ln]);

ln++;

}}int qrylkthfar(int& id, int i, int k)

int qrykthfar(int i, int k)else

}}void inslmin(int& id, int ql, int qr, int mv)

return;

}if(nodes[id].l == nodes[id].r) return;

int mid = nodes[id].mid();

if(ql <= mid)

if(qr > mid)

}void insmin(int i, int k, vtype mv)else

}}bool input()

if(ses[i].e.first != ses[i].e.second)

}m = tn;

return true;

}inline bool cmp(se a, se b)

int findfa(int u)

return k;

}void merge(int u, int v)

int kruskal(int n, int m, int& leanum, bool flag)

if(flag)

en = leanum = 0;

}sort(ses, ses + m, cmp);

for(i = ans = 0, k = 1; k < n && i < m; i++)

}else if(flag)

}if (flag)

}if(k < n) ans = inf;

return ans;

}void handlelca(int u, int v, int anc, int len)

if(dep[anc] + 2 <= dep[u])

if(dep[anc] + 2 <= dep[v])

}//qn為查詢lca的次數,qs記錄查詢lca的兩個幾點,anc記錄每次查詢的結果

int getlca(int u, int v)

if(dep[u] < dep[v]) swap(u, v);

return v;

}void lca(se* qs, int qn)

for(i = 0; i < qn; i++)

}void getpmin(int& id, int mv)

if(nodes[id].l == nodes[id].r)

getpmin(nodes[id].ls, mv);

getpmin(nodes[id].rs, mv);

}void getpmin()

}void solve()}}

int size = nes[i].size(), j;

for(j = 0; j < size; j++)

int ans = kruskal(sn, num, leanum, false);

if(ans < inf)else

}}int main()

return 0;

}

樹鏈剖分 樹鏈剖分講解

好了,這樣我們就成功解決了對樹上修改查詢邊權或點的問題。下面放上 vector v maxn int size maxn dep maxn val maxn id maxn hson maxn top maxn fa maxn 定義 int edge 1,num 1 struct tree e ma...

HDU3966 樹鏈剖分

題目 aragorn s story 題意 給一棵樹,並給定各個點權的值,然後有3種操作 i c1 c2 k 把c1與c2的路徑上的所有點權值加上k d c1 c2 k 把c1與c2的路徑上的所有點權值減去k q c 查詢節點編號為c的權值 分析 典型的樹鏈剖分題目,先進行剖分,然後用線段樹去維護即...

hdu5029 樹鏈剖分

這題絕對好題。題意很簡單,也很容易想到樹鏈剖分,之後就不太好做了。開始想的是按顏色排序,然後每次處理一種顏色,求出最優解。這樣做的話,最壞情況會退化到n 2,不可接受。之後用線段樹維護,乙個節點只存在一種顏色,而且排序之後能保證在樹中顏色不會交叉,pushdown的時候可以將兩種都不是當前正在處理的...