對每一種教派開一顆線段樹,但是很明顯空間會爆,所以動態開點線段樹,所以空間複雜度降低到nlo
gnnlogn
nlog
n,然後樹剖套線段樹,碼量稍大
#include
#define m 200009
using
namespace std;
intread()
for(
;isdigit
(ch)
;ch=
getchar()
) re=
(re<<3)
+(re<<1)
+ch-
'0';
return re*f;
}char s[10]
;int a[m]
,b[m]
,first[m]
,to[m]
,nxt[m]
,tot,cnt,tnt,rt[m]
,num[m]
,dep[m]
,size[m]
,f[m]
,son[m]
,idx[m]
,top[m]
,n,q;
struct treetr[m*
100]
;void
add(
int x,
int y)
void
upd(
int&x,
int val,
int l,
int r,
int pos)
void
del(
int&k,
int l,
int r,
int pos)
int mid=
(l+r)
>>1;
if(pos<=mid)
del(tr[k]
.l,l,mid,pos)
;else
del(tr[k]
.r,mid+
1,r,pos)
; tr[k]
.maxn=
max(tr[tr[k]
.l].maxn,tr[tr[k]
.r].maxn)
; tr[k]
.sum=tr[tr[k]
.l].sum+tr[tr[k]
.r].sum;
}int
solve1
(int k,
int l,
int r,
int ql,
int qr)
intsolve2
(int k,
int l,
int r,
int ql,
int qr)
void
dfs1
(int r,
int fa)
}void
dfs2
(int r,
int tp)
}int
query1
(int x,
int y,
int z)
if(dep[x]
)swap
(x,y)
; ans+
=solve1
(rt[z],1
,n,num[y]
,num[x]);
return ans;
}int
query2
(int x,
int y,
int z)
if(dep[x]
)swap
(x,y)
; ans=
max(ans,
solve2
(rt[z],1
,n,num[y]
,num[x]))
;return ans;
}int
main()
dfs1(1
,0),
dfs2(1
,1);
for(
int i=
1;i<=n;i++
)upd
(rt[a[i]
],b[i],1
,n,num[i]);
for(
int i=
1;i<=q;i++)if
(s[0]==
'c'&&s[1]
=='w')if
(s[0]==
'q'&&s[1]
=='s'
)printf
("%d\n"
,query1
(x,y,a[x]))
;if(s[0]==
'q'&&s[1]
=='m'
)printf
("%d\n"
,query2
(x,y,a[x]))
;}return0;
}
1,線段樹的多種構建方式需掌握(包括pushup的方式,pushdown的方式,build的方式等等) 動態開點線段樹
前置芝士 眾所周知,普通線段樹空間複雜度是 o n 4 所以當n很大的時候,如果正常的去建一顆線段樹,開4倍n空間顯然會炸記憶體 怎麼辦呢?這個時候,動態開點線段樹出現了。概念 動態開點線段樹是一類特殊的線段樹,與普通的線段樹不同的是,每乙個節點的左右兒子不是該點編號的兩倍和兩倍加一,而是現加出來的...
BZOJ 3531 旅行 樹鏈剖分 動態開點
題目鏈結 無優化版本 170行 首先樹剖可以維護樹上的鏈sum max 可以對每個宗教建一棵線段樹,那這題就很好做了 不過10 5需要動態開點 不明白為什麼nlogn不需要 就可以 不是每個insert加log個節點?操作修改完更改原數列!盲人。include include include def...
SDOI2014 旅行 樹鏈剖分 動態開點
最近學了樹鏈剖分,又可以做好多好多難題水題真是噁心開心!luogu上的主席樹標籤迷惑了我好久,結果好像只用到了主席樹的思想,主席樹的操作根本沒有.沒有宗教的限制,這道題就是樹剖的sum和max操作。但是,也很容易想到,對於每乙個宗教就建一顆樹,於是就可以每次都能夠進行查詢每個宗教的東西了。很明顯,空...