xay loves trees(主席树dfs序 标记永久化优化)
Posted 爷灬傲奈我何123
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了xay loves trees(主席树dfs序 标记永久化优化)相关的知识,希望对你有一定的参考价值。
题意:
思路:早上更新那题的强化版。用线段树尺取,或者主席树,主席树维护从根节点到链上的最大深度。每次插入新节点,询问不符合节点的id,由于区间不相交,这样的值最多一个。 每次更新一下答案就可以了。
// Problem: xay loves trees
// Contest: NowCoder
// URL: https://ac.nowcoder.com/acm/contest/11258/F
// Memory Limit: 1048576 MB
// Time Limit: 4000 ms
//
// Powered by CP Editor (https://cpeditor.org)
//#pragma GCC target("avx")
//#pragma GCC optimize(2)
//#pragma GCC optimize(3)
//#pragma GCC optimize("Ofast")
// created by myq
#include<iostream>
#include<cstdlib>
#include<string>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<climits>
#include<cmath>
#include<cctype>
#include<stack>
#include<queue>
#include<list>
#include<vector>
#include<set>
#include<map>
#include<sstream>
#include<unordered_map>
#include<unordered_set>
using namespace std;
typedef long long ll;
#define x first
#define y second
typedef pair<int,int> pii;
const int N = 400010;
const int mod=998244353;
inline int read()
{
int res=0;
int f=1;
char c=getchar();
while(c>'9' ||c<'0')
{
if(c=='-') f=-1;
c=getchar();
}
while(c>='0'&&c<='9')
{
res=(res<<3)+(res<<1)+c-'0';
c=getchar();
}
return res;
}
const int maxn=300010;
struct node{
int l;
int r;
int mx;
int lz;
}tr[maxn*32];
vector<int>v[maxn],g[maxn];
int cnt;
int n;
int dep[maxn];
int L[maxn],R[maxn];
int root[maxn];
void insert(int p,int &q,int l,int r,int ql,int qr,int d)
{
q=++cnt,tr[q]=tr[p];tr[q].mx=d;
if(l>=ql&&r<=qr) {
tr[q].lz=d;
return ;
}
int mid=l+r>>1;
if(ql<=mid) insert(tr[p].l,tr[q].l,l,mid,ql,qr,d);
if(qr>mid) insert(tr[p].r,tr[q].r,mid+1,r,ql,qr,d);
}
int query(int u,int l,int r,int ql,int qr)
{
int ans=tr[u].lz;
if(l>=ql&&r<=qr)
return tr[u].mx;
int mid=l+r>>1;
if(ql<=mid) ans=max(ans,query(tr[u].l,l,mid,ql,qr));
if(qr>mid) ans=max(ans,query(tr[u].r,mid+1,r,ql,qr));
return ans;
}
int color;
void dfs1(int u,int fa)
{
L[u]=++color;
for(auto j:v[u])
{
if(j==fa) continue;
dfs1(j,u);
}
R[u]=color;
}
int res=0;
void dfs2(int u,int fa,int d)
{
dep[u]=dep[fa]+1;
int now=max(d,query(root[fa],1,n,L[u],R[u]));
res=max(res,dep[u]-now);
insert(root[fa],root[u],1,n,L[u],R[u],dep[u]);
for(auto j:g[u])
{
if(j==fa) continue;
dfs2(j,u,now);
}
}
int main()
{
// ios::sync_with_stdio(0);
// cin.tie(0);
// cout.tie(0);
int t ;
cin>>t;
while(t--)
{
cin>>n;
for(int i=0;i<n-1;i++)
{
int a,b;
cin>>a>>b;
g[a].push_back(b);
g[b].push_back(a);
}
for(int i=0;i<n-1;i++)
{
int a,b;
cin>>a>>b;
v[a].push_back(b);
v[b].push_back(a);
}
dfs1(1,0);
dfs2(1,0,0);
cout<<res<<"\\n";
for(int i=1;i<=n;i++) v[i].clear(),g[i].clear();
cnt=0; color=0;res=0;
}
return 0;
}
/**
* In every life we have some trouble
* When you worry you make it double
* Don't worry,be happy.
**/
线段树尺取的话,我们保持窗口要么不变要么加1,很容易发现每次顶多pop一个头节点,注意回溯的时候还原原来的线段树即可。两个复杂度都是nlogn
#pragma GCC target("avx")
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast")
#include<bits/stdc++.h>
using namespace std;
const int N=300010;
vector<int>v[N],g[N];
int idx;
int L[N];
int R[N];
int stk[N];
int bs[N];
int top=0;
int ans;
int n;
struct node{
int l;
int r;
int mx;
int lz;
}tr[N<<2];
inline void build(int u,int l,int r)
{
tr[u]={l,r,0,0};
if(l==r) return;
int mid=l+r>>1;
build(u<<1,l,mid);
build(u<<1|1,mid+1,r);
}
inline void pd(int u)
{
if(tr[u].lz)
{
tr[u<<1].lz+=tr[u].lz;
tr[u<<1|1].lz+=tr[u].lz;
tr[u<<1].mx+=tr[u].lz;
tr[u<<1|1].mx+=tr[u].lz;
tr[u].lz=0;
}
}
inline void pushup(int u)
{
tr[u].mx=max(tr[u<<1].mx,tr[u<<1|1].mx);
}
inline void change(int u,int l,int r,int d)
{
// cout<<l<<" ->"<<r<<endl;
if(tr[u].l>=l && tr[u].r<=r){
tr[u].lz+=d;
tr[u].mx+=d;
return ;
}
pd(u);
int mid=tr[u].l+tr[u].r>>1;
if(l<=mid) change(u<<1,l,r,d);
if(r>mid) change(u<<1|1,l,r,d);
pushup(u);
}
inline int query(int u,int l,int r)
{
if(tr[u].l>=l && tr[u].r<=r) return tr[u].mx;
int mid=tr[u].l+tr[u].r>>1;
pd(u);
int mx=0;
if(l<=mid) mx=max(mx,query(u<<1,l,r));
if(r>mid) mx=max(mx,query(u<<1|1,l,r));
return mx;
}
int res=0;
deque<int>q;
inline void dfs2(int u,int fa)
{
q.push_back(u);
// stk[++top]=u;
int cnt=0;
int x=1;
int uu=-1;
change(1,L[u],R[u],1);
// cout<<u<<" "<<q.size()<<endl;
if(tr[1].mx<=1) res=max(res,(int)q.size());
else{
// if(q.size()>res)
{
uu=q.front();
// stk[++top]=q.front();
change(1,L[uu],R[uu],-1);
q.pop_front();
}
}
for(auto j:v[u])
{
if(j==fa) continue;
dfs2(j,u);
}
q.pop_back();
change(1,L[u],R[u],-1);
if(uu!=-1)
change(1,L[uu],R[uu],1),q.push_front(uu);
}
inline void dfs1(int u,int fa)
{
L[u]=++idx;
for(auto j:g[u])
{
if(j==fa) continue;
dfs1(j,u);
}
R[u]=idx;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
while(q.size()) q.pop_back();
idx=0;
// cin>>n;
scanf("%d",&n);
for(int i=0;i<n-1;i++)
{
int a,b;
scanf("%d%d",&a,&b);
v[a].push_back(b);
v[b].push_back(a);
}
for(int i=0;i<n-1;i++)
{
int a,b;
scanf("%d%d",&a,&b);
g[a].push_back(b);
g[b].push_back(a);
}
dfs1(1,-1);
res=0;
top=0;
build(1,1,n);
dfs2(1,-1);
printf("%d\\n",res);
for(int i=1;i<=n;i++) v[i].clear(),g[i].clear();
}
return 0;
}
以上是关于xay loves trees(主席树dfs序 标记永久化优化)的主要内容,如果未能解决你的问题,请参考以下文章
2021牛客多校7 - xay loves trees(dfs序+主席树-标记永久化)
2021牛客暑期多校训练营7 F.xay loves trees 主席树+dfs序
2021牛客暑期多校训练营7xay loves trees(dfs序,维护根出发的链)
2021牛客暑期多校训练营7 F.xay loves trees(主席树+树上尺取)