1. 程式人生 > >bzoj 3123: [Sdoi2013]森林 啟發式合併+可持久化線段樹

bzoj 3123: [Sdoi2013]森林 啟發式合併+可持久化線段樹

題意:給出一片森林,每個點有點權,要求資瓷兩個操作:詢問兩點間路徑的第k小點權;加一條邊

分析:如果沒有合併操作的話就是裸的可持久化線段樹啦。

但既然有合併操作那麼我們就每次把兩個塊的可持久化線段樹進行啟發式合併。

何為啟發式合併呢,其實就是暴力合併,把小一點的那棵樹上的主席樹全部進行重建,看上去很暴力,可據說可以證明覆雜度均攤logn,反正我是不會證了……

這題調死寶寶了~~

調了大半天,最後才發現是一開始加邊的時候忘了順帶維護並查集,導致萬年RE……

程式碼:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define N 200005  
using namespace std;

int n,m,q,tot,cnt,last[N],dep[N],fa[N][20],size[N],f[N],root[N],val[N];
struct tree{int l,r,s;}t[N*100];
struct edge{int to,next;}e[N*2];

void addedge(int u,int v)
{
	e[++cnt].to=v;e[cnt].next=last[u];last[u]=cnt;
	e[++cnt].to=u;e[cnt].next=last[v];last[v]=cnt;
}

void updata(int d)
{
	t[d].s=t[t[d].l].s+t[t[d].r].s;
}

void insert(int &d,int p,int l,int r,int x)
{
	d=++tot;
	t[d].s=t[p].s;
	if (l==r)
	{
		t[d].s++;
		return;
	}
	t[d].l=t[p].l;
	t[d].r=t[p].r;
	int mid=(l+r)/2;
	if (x<=mid) insert(t[d].l,t[p].l,l,mid,x);
	else insert(t[d].r,t[p].r,mid+1,r,x);
	updata(d);
}

void dfs(int x)
{
	for (int i=1;i<=16;i++)
		fa[x][i]=0;
	for (int i=1;i<=16;i++)
		fa[x][i]=fa[fa[x][i-1]][i-1];
	insert(root[x],root[fa[x][0]],0,1000000000,val[x]);
	for (int i=last[x];i;i=e[i].next)
	{
		if (e[i].to==fa[x][0]) continue;
		dep[e[i].to]=dep[x]+1;
		fa[e[i].to][0]=x;
		dfs(e[i].to);
	}
}

int getlca(int x,int y)
{
	if (dep[x]<dep[y]) swap(x,y);
	for (int i=16;i>=0;i--)
		if (dep[fa[x][i]]>=dep[y]) x=fa[x][i];
	if (x==y) return x;
	for (int i=16;i>=0;i--)
		if (fa[x][i]!=fa[y][i])
		{
			x=fa[x][i];y=fa[y][i];
		}
	return fa[x][0];
}

int getf(int x)
{
	if (f[x]==x) return x;
	f[x]=getf(f[x]);
	return f[x];
}

int solveQ(int r1,int r2,int r3,int r4,int l,int r,int k)
{
	if (l==r) return l;
	int mid=(l+r)/2;
	int s=t[t[r1].l].s+t[t[r2].l].s-t[t[r3].l].s-t[t[r4].l].s;
	if (s>=k) return solveQ(t[r1].l,t[r2].l,t[r3].l,t[r4].l,l,mid,k);
	else return solveQ(t[r1].r,t[r2].r,t[r3].r,t[r4].r,mid+1,r,k-s);
}

int query(int x,int y,int z)
{
	int lca=getlca(x,y);
	return solveQ(root[x],root[y],root[lca],root[fa[lca][0]],0,1000000000,z);
}

void link(int x,int y)
{
	addedge(x,y);
	int rx=getf(x),ry=getf(y);
	if (size[rx]<size[ry])
	{
		size[ry]+=size[rx];
		f[rx]=ry;
		fa[x][0]=y;
		dep[x]=dep[y]+1;
		dfs(x);
	}else
	{
		size[rx]+=size[ry];
		f[ry]=rx;
		fa[y][0]=x;
		dep[y]=dep[x]+1;
		dfs(y);
	}
}

int main()
{ 
	int x;
	scanf("%d",&x);
	scanf("%d%d%d",&n,&m,&q);
	for (int i=1;i<=n;i++)
	{
		scanf("%d",&val[i]);
		size[i]=1;
		f[i]=i;
	}
	for (int i=1;i<=m;i++)
	{
		int x,y;
		scanf("%d%d",&x,&y);
		size[getf(x)]+=size[getf(y)];
		f[getf(x)]=getf(y);
		addedge(x,y);
	}
	for (int i=1;i<=n;i++)
		if (!fa[i][0]) 
		{
			dep[i]=1;
			dfs(i);
		}
	int lastans=0;
	for (int i=1;i<=q;i++)
	{
		char ch[1];
		scanf("%s",ch);
		if (ch[0]=='Q')
		{
			int x,y,z;
			scanf("%d%d%d",&x,&y,&z);
			x^=lastans;y^=lastans;z^=lastans;
			lastans=query(x,y,z);
			printf("%d\n",lastans);
		}else
		{
			int x,y;
			scanf("%d%d",&x,&y);
			x^=lastans;y^=lastans;
			link(x,y);
		}
	}
	return 0;
}


相關推薦

bzoj 3123: [Sdoi2013]森林 啟發式合併+持久化線段

題意:給出一片森林,每個點有點權,要求資瓷兩個操作:詢問兩點間路徑的第k小點權;加一條邊 分析:如果沒有合併操作的話就是裸的可持久化線段樹啦。 但既然有合併操作那麼我們就每次把兩個塊的可持久化線段樹進行啟發式合併。 何為啟發式合併呢,其實就是暴力合併,把小一點的那棵樹上的

BZOJ-3123: [Sdoi2013]森林(主席 + LCA + 啟發式合併

題目連結:https://www.lydsy.com/JudgeOnline/problem.php?id=3123 題目大意:給出一個有n個節點的森林,接下來有m次操作,每次操作有以下兩種: 1、Q x y k : 詢問節點 x 到節點 y 這條鏈上的點的第 k 大的權值是多少。

BZOJ 3123 [Sdoi2013]森林

add str arp can test 森林 AD scan IT 題解: 啟發式合並主席樹 時間復雜度O(nlogn*logn) 空間復雜度O(nlogn*logn) Woc初始的時候也用了啟發式合並建圖,然後RE成翔了 一開始算錯了空間,下次註意 #include&

[Luogu P3302] [BZOJ 3123] [SDOI2013]森林

洛谷傳送門 題目描述 小Z有一片森林,含有NNN個節點,每個節點上都有一個非負整數作為權值。初始的時候,森林中有MMM條邊。 小Z希望執行TTT個操作,操作有兩類: Q x y k查詢點xxx到點yyy路徑上所有的權值中,第kkk小的權值是多少。此操作保證點

[BZOJ 3551] Peaks 半持久化並查集 持久化線段合並

algorithm roo i++ name def amp merge zoj 可持久化線段樹 實現 1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib>

bzoj 2588 Spoj 10628. Count on a tree (持久化線段

change lca 權值線段樹 mat sin urn problem sample des Spoj 10628. Count on a tree Time Limit: 12 Sec Memory Limit: 128 MBSubmit: 7669 Solv

BZOJ 3218 a + b Problem 網路流 持久化線段優化建圖

#include <cstdio> #include <cstring> #include <algorithm> #include <queue> #define N 200005 #define INF 100

bzoj 3218: a + b Problem 最小割+持久化線段

題意: 分析: 感覺上就是一個最小割。。。 把圖建出來之後用可持久化線段樹優化建圖即可。 程式碼: #include<iostream> #include<cstdio> #include<cstdlib> #include<

bzoj 3551: [ONTAK2010]Peaks加強版 Kruskal重構+持久化線段

題意 同bzoj3545,題解,強制線上。 分析 一開始yy出了一種用可持久化線段樹來維護可持久化的root陣列,然後其他的就像離線那樣,只是每次合併線段樹的時候不改變原來兩棵樹的兒子,而是新建節點。恩理論上好像是可以的,但是懶得寫。 這題可以用一種

主席||持久化線段||離散化||[CQOI2015]任務查詢系統||BZOJ 3932||Luogu P3168

系統 bool div 一個 記得 排序 事件 while https 題目: [CQOI2015]任務查詢系統 題解: 是一道很經典的題目。大體思路是抓優先級來當下標做主席樹,用時刻作為主席樹的版本。然而優先級範圍到1e7去了,就離散化一遍。然後把每個事件的開始(s)、結

持久化線段(主席)模板

spa std nod d+ sin 整理 ostream pan int 比賽時候寫的,這裏整理到這裏 #include <iostream> #include <cstdio> #include <cstring> using

主席持久化線段版)

可持久化線段樹 else init 修改 update 懶惰標記 logs scan amp 求區間和模板 1 struct node{ 2 int l[maxn*20],r[maxn*20]; //區間大小 maxn = 1e5時為20倍,不夠就開4

[poj2104]持久化線段入門題(主席

unique tor oot 入門題 個數 索引 方便 return 出現的次數 解題關鍵:離線求區間第k小,主席樹的經典裸題; 對主席樹的理解:主席樹維護的是一段序列中某個數字出現的次數,所以需要預先離散化,最好使用vector的erase和unique函數,很方便;如

[Luogu 3919]【模板】持久化數組(持久化線段/平衡

ins eset blog sta -s ctime it is put tex Description 如題,你需要維護這樣的一個長度為 N 的數組,支持如下幾種操作 在某個歷史版本上修改某一個位置上的值 訪問某個歷史版本上的某一位置的值 此外,每

持久化數組(持久化線段/平衡

space print align left 版本號 此外 cnblogs include 輸出格式 題目背景 UPDATE : 最後一個點時間空間已經放大 標題即題意 有了可持久化數組,便可以實現很多衍生的可持久化功能(例如:可持久化並查集) 題目描述 如題,你需要維護

聰明的質檢員 [NOIP 2011] [持久化線段]

ora space pla des turn num ans max inf Description 小 T 是一名質量監督員,最近負責檢驗一批礦產的質量。這批礦產共有n個礦石,從 1 到n逐一編號,每個礦石都有自己的重量wi以及價值vi。檢驗礦產的流程是: 1.

【BZOJ4704】旅行 鏈剖分+持久化線段

-s 編號 不能 ets include 出發 oot %d rip 【BZOJ4704】旅行 Description 在Berland,有n個城堡。每個城堡恰好屬於一個領主。不同的城堡屬於不同的領主。在所有領主中有一個是國王,其他的每個領主都直接隸屬於另一位領主,

【BZOJ3681】Arietta 鏈剖分+持久化線段優化建圖+網絡流

des 持久化 -s 過程 void 但是 陽光 建圖 == 【BZOJ3681】Arietta Description Arietta 的命運與她的妹妹不同,在她的妹妹已經走進學院的時候,她仍然留在山村中。但是她從未停止過和戀人 Velding 的書信往來。一天,

【模板】持久化線段 1(主席

base math 一次 數據 mar 指定 das min 第k小 題目背景 這是個非常經典的主席樹入門題——靜態區間第K小 數據已經過加強,請使用主席樹。同時請註意常數優化 題目描述 如題,給定N個正整數構成的序列,將對於指定的閉區間

洛谷P3402 【模板】持久化並查集(持久化線段線段

std 樹節點 https case 深度 build eof spa 復雜度 orz TPLY 巨佬,題解講的挺好的。 這裏重點梳理一下思路,做一個小小的補充吧。 寫可持久化線段樹,葉子節點維護每個位置的fa,利用每次只更新一個節點的特性,每次插入\(logN\)個節點,