P3899 [湖南集训]更为厉害(线段树合并、长链剖分、二维数点)
生活随笔
收集整理的這篇文章主要介紹了
P3899 [湖南集训]更为厉害(线段树合并、长链剖分、二维数点)
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
P3899 [湖南集訓(xùn)]更為厲害
- 若 deepb<deepa\text{deep}_b<\text{deep}_adeepb?<deepa?:c 在點(diǎn) a 的子樹中,根據(jù)乘法原理計(jì)算答案為 min?(deepa,k)?(sza?1)\min(\text{deep}_a,k)?(\text{sz}_a?1)min(deepa?,k)?(sza??1)
- 若 deepb>deepa\text{deep}_b>\text{deep}_adeepb?>deepa?:c 在點(diǎn) b 的子樹中,所以此時(shí)每個(gè)點(diǎn) b 的貢獻(xiàn)為 szb?1\text{sz}_b?1szb??1
對(duì)于上述條件,滿足深度限制即可。
Code1
線段樹合并暴力合并子樹
1.80s / 90.65MB / 1.82KB C++17
#include<bits/stdc++.h>using namespace std; using ll=long long; constexpr int N=300010; int h[N],e[2*N],ne[2*N],idx; void add(int a,int b){e[idx]=b,ne[idx]=h[a],h[a]=idx++;} int n,q; struct node {int l,r;ll v; }tree[N*40]; int root[N],cnt; void insert(int &u,int l,int r,int pos,ll v) {if(!u) u=++cnt;if(l==r) return tree[u].v+=v,void();int mid=l+r>>1;if(pos<=mid) insert(tree[u].l,l,mid,pos,v);elseinsert(tree[u].r,mid+1,r,pos,v);tree[u].v=tree[tree[u].l].v+tree[tree[u].r].v; } ll query(int u,int l,int r,int L,int R) {if(!u) return 0ll;if(L<=l&&r<=R) return tree[u].v;int mid=l+r>>1;ll v=0;if(L<=mid)v+=query(tree[u].l,l,mid,L,R);if(R>mid)v+=query(tree[u].r,mid+1,r,L,R);return v; } int merge(int x,int y) {if(!x||!y) return x+y;int u=++cnt;tree[u].v=tree[x].v+tree[y].v;tree[u].l=merge(tree[x].l,tree[y].l);tree[u].r=merge(tree[x].r,tree[y].r);return u; }int dep[N],sz[N];void dfs(int u,int fa) {dep[u]=dep[fa]+1;sz[u]=1;for(int i=h[u];i!=-1;i=ne[i]){int v=e[i];if(v==fa) continue;dfs(v,u);sz[u]+=sz[v];root[u]=merge(root[u],root[v]);}insert(root[u],1,n,dep[u],sz[u]-1); }int main() {ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);cin>>n>>q;memset(h,-1,sizeof h);for(int i=1;i<n;i++){int u,v;cin>>u>>v;add(u,v),add(v,u);}dfs(1,0);while(q--){int p,k;cin>>p>>k;ll ans=0;ans+=1ll*min(k,dep[p]-1)*(sz[p]-1);ans+=query(root[p],1,n,dep[p]+1,dep[p]+k);cout<<ans<<'\n';}return 0; }Code2
長(zhǎng)鏈剖分
1.51s / 48.94MB / 1.60KB C++17
#include<bits/stdc++.h>using namespace std; using ll=long long; constexpr int N=300010; int h[N],e[2*N],ne[2*N],idx; void add(int a,int b){e[idx]=b,ne[idx]=h[a],h[a]=idx++;} ll ans[N]; int n,m; int ht[N],son[N],sz[N],dep[N]; void dfs1(int u,int fa) {sz[u]=1;dep[u]=dep[fa]+1;for(int i=h[u];i!=-1;i=ne[i]){int v=e[i];if(v==fa) continue;dfs1(v,u);sz[u]+=sz[v];if(ht[son[u]]<ht[v]) son[u]=v;}ht[u]=ht[son[u]]+1; } ll pool[N]; ll *f[N],*now=pool; ll tag[N]; vector<pair<int,int>> q[N]; void dfs2(int u,int fa) {if(son[u]){f[son[u]]=f[u]+1;dfs2(son[u],u);tag[u]=tag[son[u]]+sz[son[u]]-1;}for(int i=h[u];i!=-1;i=ne[i]){int v=e[i];if(v==fa||v==son[u]) continue;f[v]=now;now+=ht[v];dfs2(v,u);tag[u]+=tag[v]+sz[v]-1;for(int j=1;j<ht[v];j++)f[u][j]+=f[v][j-1];//+tag[v]+sz[v]-1;}f[u][0]-=tag[u];for(auto [k,id]:q[u]) ans[id]=1ll*min(dep[u]-1,k)*(sz[u]-1)+f[u][min(k,ht[u]-1)]+tag[u]; }int main() {ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);cin>>n>>m;memset(h,-1,sizeof h);for(int i=1;i<n;i++){int u,v;cin>>u>>v;add(u,v),add(v,u);}for(int i=1;i<=m;i++){int p,k;cin>>p>>k;q[p].push_back({k,i});}dfs1(1,0);f[1]=now;now+=ht[1];dfs2(1,0);for(int i=1;i<=m;i++) cout<<ans[i]<<'\n';return 0; }Code3
主席樹二維數(shù)點(diǎn)
2.58s / 107.27MB / 1.85KB C++17
#include<bits/stdc++.h>using namespace std; using ll=long long; constexpr int N=300010; int h[N],e[2*N],ne[2*N],idx; void add(int a,int b){e[idx]=b,ne[idx]=h[a],h[a]=idx++;} int n,q; struct node {int l,r;ll v; }tree[N*40]; int rt[N],cnt; void insert(int &u,int o,int l,int r,int pos,ll v) {tree[u=++cnt]=tree[o];tree[u].v+=v;if(l==r) return;int mid=l+r>>1;if(pos<=mid) insert(tree[u].l,tree[o].l,l,mid,pos,v);elseinsert(tree[u].r,tree[o].r,mid+1,r,pos,v); } ll query(int u,int l,int r,int L,int R) {if(!u) return 0ll;if(L<=l&&r<=R) return tree[u].v;int mid=l+r>>1;ll v=0;if(L<=mid)v+=query(tree[u].l,l,mid,L,R);if(R>mid)v+=query(tree[u].r,mid+1,r,L,R);return v; }int dep[N],sz[N]; int L[N],timestamp,R[N];void dfs1(int u,int fa) {L[u]=++timestamp;dep[u]=dep[fa]+1;sz[u]=1;for(int i=h[u];i!=-1;i=ne[i]){int v=e[i];if(v==fa) continue;dfs1(v,u);sz[u]+=sz[v];}R[u]=timestamp;} void dfs2(int u,int fa) {insert(rt[L[u]],rt[L[u]-1],1,n,dep[u],sz[u]-1);for(int i=h[u];i!=-1;i=ne[i]){int v=e[i];if(v==fa) continue;dfs2(v,u);} } int main() {ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);cin>>n>>q;memset(h,-1,sizeof h);for(int i=1;i<n;i++){int u,v;cin>>u>>v;add(u,v),add(v,u);}dfs1(1,0);dfs2(1,0);while(q--){int u,k;cin>>u>>k;ll ans=0;ans+=1ll*min(k,dep[u]-1)*(sz[u]-1);ans+=query(rt[R[u]],1,n,dep[u]+1,dep[u]+k)-query(rt[L[u]-1],1,n,dep[u]+1,dep[u]+k);cout<<ans<<'\n';}return 0; }本質(zhì)上線段樹合并是通過該節(jié)點(diǎn)的子樹構(gòu)建當(dāng)前樹直接得到子樹信息,而主席樹是通過轉(zhuǎn)化dfs序構(gòu)建前綴樹,通過作差得到子樹的信息。
如果某些信息不支持做差得到,那么主席樹的做法將失效,而線段樹合并仍然適用
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)總結(jié)
以上是生活随笔為你收集整理的P3899 [湖南集训]更为厉害(线段树合并、长链剖分、二维数点)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: The 2020 ICPC Asia M
- 下一篇: 关于人生的网名 和人生有关的网名