P4787 [BalkanOI2018]Minmaxtree 题解
逸延丁真,鉴定为大胖题。
很自然想到树剖一下维护第
我们有结论:存在一种合法的构造,使得第
简单证明一下,首先边权不能取
于是问题抽象成有
这是一个二分图最大匹配问题,左边
思路很自然,然而有树剖和网络流二合一,代码很长。
时间复杂度
#include<iostream>
#include<cstdio>
#include<vector>
#include<queue>
#include<map>
using namespace std;
inline int read()
{
int x=0;
char c=getchar();
while(c<'0'||c>'9')
c=getchar();
while(c>='0'&&c<='9')
{
x=(x<<1)+(x<<3)+(c^48);
c=getchar();
}
return x;
}
struct flow
{
struct edge
{
int nxt,to,weight;
}e[1000001<<3];
int tot=1,s,t,h[200001],dep[200001],cur[200001],ans;
bool vis[200001];
inline void add(int x,int y,int w)
{
e[++tot]={h[x],y,w};
h[x]=tot;
}
inline bool bfs()
{
queue<int> q;
for(int i=0;i<=t;++i)
{
vis[i]=0;
dep[i]=0x3f3f3f3f;
cur[i]=h[i];
}
dep[s]=0;
q.emplace(s);
while(!q.empty())
{
int k=q.front();
q.pop();
vis[k]=0;
for(int i=h[k];i;i=e[i].nxt)
if(e[i].weight&&dep[e[i].to]>dep[k]+1)
{
dep[e[i].to]=dep[k]+1;
if(!vis[e[i].to])
{
vis[e[i].to]=1;
q.emplace(e[i].to);
}
}
}
return dep[t]^dep[0];
}
inline int dfs(int k,int f)
{
if(k==t)
{
ans+=f;
return f;
}
int r=0,used=0;
for(int i=cur[k];i;i=e[i].nxt)
{
cur[k]=i;
if(e[i].weight&&dep[e[i].to]==dep[k]+1)
if((r=dfs(e[i].to,min(e[i].weight,f-used))))
{
e[i].weight-=r;
e[i^1].weight+=r;
used+=r;
if(f==used)
break;
}
}
return used;
}
inline void dinic()
{
while(bfs())
dfs(s,1<<30);
}
}flow;
int n,m,w[70001],ans[70001],dep[70001],fa[70001],s[70001],son[70001],top[70001],cnt,dfn[70001],val[70001<<2][2],tag[70001<<2][2];
map<int,int> mp;
vector<int> v[70001];
inline int ls(int k)
{
return k<<1;
}
inline int rs(int k)
{
return k<<1|1;
}
inline void push_up(int k)
{
val[k][0]=max(val[ls(k)][0],val[rs(k)][0]);
val[k][1]=min(val[ls(k)][1],val[rs(k)][1]);
}
inline void push_down(int k)
{
if(tag[k][0]>=0)
{
val[ls(k)][0]=max(val[ls(k)][0],tag[k][0]);
val[rs(k)][0]=max(val[rs(k)][0],tag[k][0]);
tag[ls(k)][0]=max(tag[ls(k)][0],tag[k][0]);
tag[rs(k)][0]=max(tag[rs(k)][0],tag[k][0]);
tag[k][0]=-1;
}
if(tag[k][1]<=1e9)
{
val[ls(k)][1]=min(val[ls(k)][1],tag[k][1]);
val[rs(k)][1]=min(val[rs(k)][1],tag[k][1]);
tag[ls(k)][1]=min(tag[ls(k)][1],tag[k][1]);
tag[rs(k)][1]=min(tag[rs(k)][1],tag[k][1]);
tag[k][1]=1e9+7;
}
}
inline void build(int k,int l,int r)
{
tag[k][0]=-1;
tag[k][1]=1e9+7;
if(l==r)
{
val[k][0]=-1;
val[k][1]=1e9+7;
return;
}
int mid=(l+r)>>1;
build(ls(k),l,mid);
build(rs(k),mid+1,r);
push_up(k);
}
inline void update1(int nl,int nr,int l,int r,int k,int p)
{
if(nl>nr)
return;
if(l>=nl&&r<=nr)
{
val[k][0]=max(val[k][0],p);
tag[k][0]=max(tag[k][0],p);
return;
}
push_down(k);
int mid=(l+r)>>1;
if(nl<=mid)
update1(nl,nr,l,mid,ls(k),p);
if(nr>mid)
update1(nl,nr,mid+1,r,rs(k),p);
push_up(k);
}
inline void update2(int nl,int nr,int l,int r,int k,int p)
{
if(nl>nr)
return;
if(l>=nl&&r<=nr)
{
val[k][1]=min(val[k][1],p);
tag[k][1]=min(tag[k][1],p);
return;
}
push_down(k);
int mid=(l+r)>>1;
if(nl<=mid)
update2(nl,nr,l,mid,ls(k),p);
if(nr>mid)
update2(nl,nr,mid+1,r,rs(k),p);
push_up(k);
}
inline pair<int,int> query(int node,int l,int r,int k)
{
if(l==r)
return {val[k][0],val[k][1]};
push_down(k);
int mid=(l+r)>>1;
if(node<=mid)
return query(node,l,mid,ls(k));
return query(node,mid+1,r,rs(k));
}
inline void up1(int x,int y,int p)
{
while(top[x]^top[y])
{
if(dep[top[x]]<dep[top[y]])
swap(x,y);
update1(dfn[top[x]],dfn[x],1,n,1,p);
x=fa[top[x]];
}
if(dep[x]>dep[y])
swap(x,y);
update1(dfn[x]+1,dfn[y],1,n,1,p);
}
inline void up2(int x,int y,int p)
{
while(top[x]^top[y])
{
if(dep[top[x]]<dep[top[y]])
swap(x,y);
update2(dfn[top[x]],dfn[x],1,n,1,p);
x=fa[top[x]];
}
if(dep[x]>dep[y])
swap(x,y);
update2(dfn[x]+1,dfn[y],1,n,1,p);
}
inline void dfs1(int k,int f,int deep)
{
dep[k]=deep;
fa[k]=f;
s[k]=1;
for(int i:v[k])
{
if(i==f)
continue;
dfs1(i,k,deep+1);
s[k]+=s[i];
if(s[i]>s[son[k]])
son[k]=i;
}
}
inline void dfs2(int k,int t)
{
top[k]=t;
dfn[k]=++cnt;
if(!son[k])
return;
dfs2(son[k],t);
for(int i:v[k])
{
if(i==fa[k]||i==son[k])
continue;
dfs2(i,i);
}
}
int main()
{
freopen("minmaxtree.in","r",stdin);
freopen("minmaxtree.out","w",stdout);
n=read();
for(int i=1;i<n;++i)
{
int x=read(),y=read();
v[x].emplace_back(y);
v[y].emplace_back(x);
}
dfs1(1,0,1);
dfs2(1,1);
build(1,1,n);
m=read();
flow.s=n+m+1;
flow.t=flow.s+1;
for(int i=1;i<=m;++i)
{
flow.add(flow.s,i,1);
flow.add(i,flow.s,0);
char opt=getchar();
while(opt!='M'&&opt!='m')
opt=getchar();
int x=read(),y=read();
w[i]=read();
if(opt=='m')
up1(x,y,w[i]);
if(opt=='M')
up2(x,y,w[i]);
mp[w[i]]=i;
}
for(int i=2;i<=n;++i)
{
ans[i]=-1;
flow.add(i+m,flow.t,1);
flow.add(flow.t,i+m,0);
pair<int,int> w=query(dfn[i],1,n,1);
if(w.first>=0)
{
flow.add(mp[w.first],i+m,1);
flow.add(i+m,mp[w.first],0);
}
if(w.second<=1e9)
{
flow.add(mp[w.second],i+m,1);
flow.add(i+m,mp[w.second],0);
}
}
flow.dinic();
//cout<<flow.ans<<'\n';
for(int k=1;k<=m;++k)
for(int i=flow.h[k];i;i=flow.e[i].nxt)
if(!flow.e[i].weight&&flow.e[i].to>m&&flow.e[i].to<=n+m)
{
ans[flow.e[i].to-m]=w[k];
break;
}
for(int i=2;i<=n;++i)
{
if(ans[i]!=-1)
{
cout<<fa[i]<<" "<<i<<" "<<ans[i]<<'\n';
continue;
}
pair<int,int> tmp=query(dfn[i],1,n,1);
if(tmp.first==-1)
tmp.first=0;
cout<<fa[i]<<" "<<i<<" "<<tmp.first<<'\n';
}
return 0;
}