突然發現剖分樹可以在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的時候可以將兩種都不是當前正在處理的...