先考慮乙個節點怎麼樣才會被走到。
對於乙個權值為為 x
xx 的節點,它的左子樹內的節點有可能被走到僅當其權值小於 x
xx,右子樹內的節點有可能被走到僅當其權值大於 xxx。
那麼樹上每條邊相當於給這條邊以下的子樹加了乙個大於或是小於的限制,詢問乙個節點時,只要判斷這個節點的權值是否同時滿足到根路徑上所有邊的限制即可。
我們可以用樹鏈剖分加線段樹維護這個限制,單點修改很好處理,子樹翻轉相當於取反子樹內所有限制的符號,線段樹同時維護一下翻轉後的限制,打標記維護即可。時間複雜度 o(m
log2n
)o(m\log ^2 n)
o(mlog2n
)。
#include
#define n 100010
#define inf 0x7fffffff
using
namespace std;
struct part
part
(int l,
int r)
}p[n<<2]
[2];
part operator
+(part a,part b)
int n,m,rt,a[n]
;int tot,ch[n][2
],from[n]
,fa[n]
,size[n]
,son[n]
,dep[n]
,top[n]
,id[n]
,rk[n]
;int ffrom[n<<2]
;bool now[n<<2]
,rev[n<<2]
;//maxn[u][0]未翻轉最大值,minn[u][0]未翻轉最小值
//maxn[u][1]翻轉後最大值,minn[u][0]翻轉後最小值
void
dfs(
int u)
}void
dfs1
(int u,
int tp)
void
calc
(int k,
int l)if(
!ffrom[k]
)else
}voidup(
int k)
void
downn
(int k)
void
down
(int k)
}void
build
(int k,
int l,
int r)
int mid=
(l+r)
>>1;
build
(k<<
1,l,mid)
;build
(k<<1|
1,mid+
1,r);up
(k);
}void
update
(int k,
int l,
int r,
int x)
int mid=
(l+r)
>>1;
if(x<=mid)
update
(k<<
1,l,mid,x)
;else
update
(k<<1|
1,mid+
1,r,x);up
(k);
}void
make_tag
(int k,
int l,
int r,
int ql,
int qr)
down
(k);
int mid=
(l+r)
>>1;
if(ql<=mid)
make_tag
(k<<
1,l,mid,ql,qr);if
(qr>mid)
make_tag
(k<<1|
1,mid+
1,r,ql,qr);up
(k);
}part query
(int k,
int l,
int r,
int ql,
int qr)
intmain()
}for
(int i=
1;i<=n;i++)}
dfs(rt)
,dfs1
(rt,rt)
;build(1
,1,n);
while
(m--)}
if(opt==2)
}if(opt==3)
if(ans.minn<=a[u]
&&a[u]
<=ans.maxn)
puts
("yes");
else
puts
("no");
}}return0;
}/*3 710 2 3
5 0 0
5 0 0
3 13 2
3 31 3 100
3 32 1
3 3*/
樹鏈剖分 樹鏈剖分講解
好了,這樣我們就成功解決了對樹上修改查詢邊權或點的問題。下面放上 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...
演算法入門 樹鏈剖分 輕重鏈剖分
目錄 3.0 求 lca 4.0 利用資料結構維護資訊 5.0 例題 參考資料 資料結構入門 線段樹 發表於 2019 11 28 20 39 dfkuaid 摘要 線段樹的基本 建樹 區間查詢 單點修改 及高階操作 區間修改 單點查詢 區間修改 區間查詢 標記下傳 標記永久化 閱讀全文 樹鏈剖分用...
樹鏈剖分 樹剖換根
這是一道模板題。給定一棵 n 個節點的樹,初始時該樹的根為 1 號節點,每個節點有乙個給定的權值。下面依次進行 m 個操作,操作分為如下五種型別 換根 將乙個指定的節點設定為樹的新根。修改路徑權值 給定兩個節點,將這兩個節點間路徑上的所有節點權值 含這兩個節點 增加乙個給定的值。修改子樹權值 給定乙...