1 条题解
-
0
Problem
给定一棵 个点的树, 次询问,每次给定 ,查询:
$$\max\limits_{\substack{[l',r']\subseteq [l,r]\\r'-l'+1\ge k}} dep_{\operatorname{lca}([l',r'])}$$的值。
。
Solution
闲话:
场上 40min 写完,没调试,一发通过大样例!!!
杭师大机子极限数据 1.9s,应该能过吧???
Part 1
考虑一个类似于支配点对的东西,具体的,我们对于每个点 ,我们找出他子树内的每一个极长连续段 ,并且满足 。
我们断言:这样子的点对 只有 个。
- 证明:从子树合并角度来看太困难,我们不妨视作有一张图,每次子树合并的时候相当于会连接若干个 (也就是 ),每连接一条会新产生一个极长段,我们会恰好连接 次,所以最多只会有 个点对。
实时维护子树内的极长连续段,使用 dsu on tree 容易在 复杂度内找出所有点对。上面那个是本人在考场上写的东西,但是根据上面的证明,我们注意到其实存在更简单地找连续段地方法:
- 我们将一个操作 挂在 处,然后倒着扫描 ,每次执行挂在这个深度的操作,时刻 维护连续段并加入支配点对集合 即可。
连续段可以使用并查集或者
set维护,复杂度 。或者有更简单地做法:构造序列 ,求 的笛卡尔树则每个节点管辖的区间就是一个支配对。
Part 2
接下来问题变为:
- 给定若干个线段,线段带权,每次询问给定一个线段,查询和该线段交集不小于 的所有线段中的权值最大值。
考虑所有能对询问 产生贡献的线段 长什么样子:
- 。
- 。
- 。
- 。
最后一种可以拍入前两种中,下面略去不谈,第三种显然合法,所以偏序关系只有 两维,扫描线即可;剩下两种(下面以第一种为例)除了 和 外还有交集不小于 的偏序关系,看起来像是三维偏序,但我们仔细分析:
- 如果我们保证 ,则交集不小于 实际上是 。
我们考虑从大到小扫描 ,每次把 的值挂在左端点 处,每次就是询问 的区间 。
同理处理第二种情况,并且我们发现其实这样子顺手把第四种算好了。
这样子复杂度就是 了。
Code
#include<bits/stdc++.h> // #define int long long // #pragma GCC optimize(3,"Ofast","inline") #define debug(...) fprintf(stderr,__VA_ARGS__) #define ll long long #define bint __int128 #define ull unsigned long long #define uint unsigned int #define ld double #define PII pair<int,int> #define chkmax(a,b) a=max(a,b) #define chkmin(a,b) a=min(a,b) #define rep(k,l,r) for(int k=l;k<=r;++k) #define per(k,r,l) for(int k=r;k>=l;--k) #define cl(f,x) memset(f,x,sizeof(f)) #define pcnt(x) __builtin_popcount(x) #define lg(x) (31-__builtin_clz(x)) using namespace std; void file_IO() { freopen("query.in","r",stdin); freopen("query.out","w",stdout); } bool M1; namespace IO { char Is[(1<<21)+10],Os[(1<<21)+10]; int Ipt,Opt; char gc() { if(Ipt==1<<21) Ipt=0; if(!Ipt) Is[fread(Is,1,1<<21,stdin)]=0; return Is[Ipt++]; } void flush() { fwrite(Os,1,Opt,stdout); Opt=0; } void pc(char x) { if(Opt==1<<21) flush(); Os[Opt++]=x; } int read() { int x=0,f=1; char ch=gc(); while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=gc(); } while(ch<='9'&&ch>='0') x=(x<<3)+(x<<1)+ch-'0',ch=gc(); return x*f; } int tt[100]; void write(int x) { if(x<0) pc('-'),x=-x; if(!x) { pc('0'); return; } int len=0; while(x) tt[++len]=x%10,x/=10; per(i,len,1) pc(tt[i]+48); } } using namespace IO; const int INF=0x3f3f3f3f; const ll INFLL=0x3f3f3f3f3f3f3f3f; const ld eps=1e-9; const int N=5e5+5; int head[N],len; struct node { int to,nxt; }; node edge[N<<1]; void add_edge(int u,int v) { edge[++len]={v,head[u]}; head[u]=len; } int d[N],pa[N],max_son[N],siz[N]; void dfs(int u,int fa) { d[u]=d[fa]+1; pa[u]=fa; siz[u]=1; for(int i=head[u];i;i=edge[i].nxt) { int v=edge[i].to; if(v!=fa) { dfs(v,u); if(siz[v]>siz[max_son[u]]) max_son[u]=v; siz[u]+=siz[v]; } } } int top[N],dfn[N],p; void dfs1(int u,int w) { top[u]=w; dfn[u]=++p; if(max_son[u]) dfs1(max_son[u],w); for(int i=head[u];i;i=edge[i].nxt) { int v=edge[i].to; if(v!=max_son[u]&&v!=pa[u]) dfs1(v,v); } } int lca(int u,int v) { while(top[u]!=top[v]) { if(d[top[u]]>d[top[v]]) swap(u,v); v=pa[top[v]]; } return d[u]<d[v]? u:v; } struct info { int l,r,k; }; vector<info> vec[N],upd[N],ask[N],assk[N]; void ins(int l,int r,int v) { vec[r].push_back({l,r,v}); upd[r-l+1].push_back({l,r,v}); } struct dsu { int fa[N]; void init(int n) { rep(i,1,n) fa[i]=i; } int find(int x) { if(fa[x]!=x) fa[x]=find(fa[x]); return fa[x]; } void merge(int u,int v) { u=find(u); v=find(v); if(u!=v) fa[u]=v; } bool same(int u,int v) { return find(u)==find(v); } }; dsu pre,suf; void link(int k,int v) { //link(k,k+1) int l=pre.find(k),r=suf.find(k+1); ins(l,r,v); pre.merge(k+1,k); suf.merge(k,k+1); } vector<int> tmp[N]; struct SGT { struct node { int l,r,val; }; node tree[N<<2]; #define ls(k) (k<<1) #define rs(k) (k<<1|1) void push_up(int k) { tree[k].val=max(tree[ls(k)].val,tree[rs(k)].val); } void build(int k,int l,int r) { tree[k].l=l; tree[k].r=r; if(l==r) return; int mid=(l+r)>>1; build(ls(k),l,mid); build(rs(k),mid+1,r); } void update(int k,int qx,int val) { if(tree[k].l==tree[k].r) { chkmax(tree[k].val,val); return; } if(qx<=tree[ls(k)].r) update(ls(k),qx,val); else update(rs(k),qx,val); push_up(k); } int query(int k,int ql,int qr) { if(ql>qr) return 0; if(ql<=tree[k].l&&tree[k].r<=qr) return tree[k].val; int res=0; if(ql<=tree[ls(k)].r) chkmax(res,query(ls(k),ql,qr)); if(qr>=tree[rs(k)].l) chkmax(res,query(rs(k),ql,qr)); return res; } #undef ls #undef rs }; SGT T1,T2,T3; int ans[N]; void solve() { int n=read(); rep(i,2,n) { int u=read(),v=read(); add_edge(u,v); add_edge(v,u); } dfs(1,0); dfs1(1,1); rep(i,1,n-1) tmp[d[lca(i,i+1)]].push_back(i); pre.init(n); suf.init(n); rep(i,1,n) ins(i,i,d[i]); per(i,n,1) { for(auto x:tmp[i]) link(x,i); } int q=read(); rep(i,1,q) { int l=read(),r=read(),k=read(); assk[r].push_back({l,r,i}); ask[k].push_back({l,r,i}); } T1.build(1,1,n); T2.build(1,1,n); per(i,n,1) { for(auto x:upd[i]) { int l=x.l,r=x.r,k=x.k; T1.update(1,l,k); T2.update(1,r,k); } for(auto x:ask[i]) { int l=x.l,r=x.r,k=x.k; chkmax(ans[k],T1.query(1,l,r-i+1)); chkmax(ans[k],T2.query(1,l+i-1,r)); } } T3.build(1,1,n); per(i,n,1) { for(auto x:vec[i]) T3.update(1,x.l,x.k); for(auto x:assk[i]) chkmax(ans[x.k],T3.query(1,1,x.l)); } rep(i,1,q) write(ans[i]),pc('\n'); flush(); } bool M2; // g++ query.cpp -std=c++14 -Wall -O2 -o query signed main() { file_IO(); int testcase=1; // scanf("%d",&testcase); while(testcase--) solve(); debug("used time = %dms\n",(signed)(1000*clock()/CLOCKS_PER_SEC)); debug("used memory = %dMB\n",(signed)((&M1-&M2)/1024/1024)); return 0; }
- 1
信息
- ID
- 2560
- 时间
- 2000ms
- 内存
- 512MiB
- 难度
- 10
- 标签
- 递交数
- 6
- 已通过
- 3
- 上传者