BZOJ 3123 SDOI 2013 森林 可持久化線段樹+啟發學習法合并

來源:互聯網
上載者:User

標籤:bzoj   sdoi2013   線段樹   可持久化線段樹   啟發學習法合并   

題目大意:給出一個森林,每個節點都有一個權值。有若干加邊操作,問兩點之間路徑上的第k小權值是多少。


思路:這題和COT1比較像,但是多了串連操作。這樣就只能暴力合并連個樹。啟發學習法合并會保證時間複雜度不至於太大。然後就是用可持久化線段樹維護一個樹的資訊,按照dfs序來建樹,每個節點的可持久化鏈的參考版本就是它父親的版本。之後利用權值線段樹可區間加減的特性,用f[x] + f[y] - f[lca] - f[father[lca]]來計算權值。


CODE:

#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#define MAX 80010#define MAX_RANGE 1000000000#define POOL_SIZE 20000000using namespace std;struct PersSegTree{PersSegTree *son[2];int num;}mempool[POOL_SIZE],*C = mempool;int points,edges,asks;int src[MAX];int head[MAX],total;int next[MAX << 1],aim[MAX << 1];int f[MAX],cnt[MAX];int xx[MAX],top,father[MAX][20];int deep[MAX];PersSegTree *tree[MAX];char s[10];PersSegTree *NewNode(PersSegTree *_,PersSegTree *__,int ___){C->son[0] = _;C->son[1] = __;C->num = ___;return C++;}void Initialize(){for(int i = 1;i <= points; ++i)f[i] = i,cnt[i] = 1;tree[0] = NewNode(C,C,0);}inline void Add(int x,int y){next[++total] = head[x];aim[total] = y;head[x] = total;}int Find(int x){if(f[x] == x)return x;return f[x] = Find(f[x]);}void Unite(int x,int y){int fx = Find(x);int fy = Find(y);cnt[fx] += cnt[fy];f[fy] = fx;}void SparseTable(){for(int j = 1;j <= 19; ++j)for(int i = 1;i <= top; ++i)father[xx[i]][j] = father[father[xx[i]][j - 1]][j - 1];}int GetLCA(int x,int y){if(deep[x] < deep[y])swap(x,y);for(int i = 19; ~i; --i)if(deep[father[x][i]] >= deep[y])x = father[x][i];if(x == y)return x;for(int i = 19; ~i; --i)if(father[x][i] != father[y][i])x = father[x][i],y = father[y][i];return father[x][0];}PersSegTree *BuildTree(PersSegTree *consult,int l,int r,int val){if(l == r)return NewNode(NULL,NULL,consult->num + 1);int mid = (l + r) >> 1;if(val <= mid)return NewNode(BuildTree(consult->son[0],l,mid,val),consult->son[1],consult->num + 1);elsereturn NewNode(consult->son[0],BuildTree(consult->son[1],mid + 1,r,val),consult->num + 1);}void DFS(int x,int last){deep[x] = deep[last] + 1;father[x][0] = last;xx[++top] = x;tree[x] = BuildTree(tree[last],0,MAX_RANGE,src[x]);for(int i = head[x];i;i = next[i]) {if(aim[i] == last)continue;DFS(aim[i],x);}}int GetKth(PersSegTree *_l,PersSegTree *_r,PersSegTree *f,PersSegTree *p,int l,int r,int k){if(l == r)return l;int mid = (l + r) >> 1;int temp = _l->son[0]->num + _r->son[0]->num - f->son[0]->num - p->son[0]->num;if(k <= temp)return GetKth(_l->son[0],_r->son[0],f->son[0],p->son[0],l,mid,k);return GetKth(_l->son[1],_r->son[1],f->son[1],p->son[1],mid + 1,r,k - temp);}int main(){scanf("%*d%d%d%d",&points,&edges,&asks);Initialize();for(int i = 1;i <= points; ++i)scanf("%d",&src[i]);for(int x,y,i = 1;i <= edges; ++i) {scanf("%d%d",&x,&y);Add(x,y),Add(y,x);Unite(x,y);}for(int i = 1;i <= points; ++i)if(!deep[i])DFS(i,0);SparseTable();int last_ans = 0;for(int x,y,z,i = 1;i <= asks; ++i) {scanf("%s%d%d",s,&x,&y);x ^= last_ans,y ^= last_ans;if(s[0] == 'Q') {scanf("%d",&z);z ^= last_ans;int lca = GetLCA(x,y);printf("%d\n",last_ans = GetKth(tree[x],tree[y],tree[lca],tree[father[lca][0]],0,MAX_RANGE,z));}else {int fx = Find(x);int fy = Find(y);if(cnt[fx] > cnt[fy])swap(x,y);top = 0;DFS(x,y);Unite(x,y);Add(x,y),Add(y,x);SparseTable();}}return 0;}


BZOJ 3123 SDOI 2013 森林 可持久化線段樹+啟發學習法合并

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.