9.1-9.7训练改题
9.1-9.7
2019-2020 XX Open Cup, Grand Prix of Korea
J Parklife
题意
\(n\)个带权的区间,选一些作为覆盖,整个区间的覆盖是所有小区间的覆盖次数的最大值,权值是选出的权值和,求覆盖次数分别为\(1-n\)的最大权。
题解
首先这样的结构可以抽象成括号序,也就可以变成树的结构,最简单的树形dp是\(n^2\)的复杂度的,\(dp_{i,j}\)表示\(i\)为根的子树中覆盖次数是\(j\)的最大答案。
我们可以发现,字树答案是单调不降的,并且答案的差分是单调不升的。也就是说,我们可以把\(j\)的答案拆分每次选取\(1\)的答案的前缀和第\(j\)项。同时子树之间是互不影响的。这样的话,把每个节点的答案存进优先队列里,利用启发式合并的过程,合并到根。就能得到答案。
#include <bits/stdc++.h>
#define LL long long
#define pb push_back
#define mp make_pair
#define pii pair<int,int>
#define fi first
#define se second
#define lc nd<<1
#define rc nd<<1|1
#define lowbit(x) (x&(-x))
#define pLL pair<LL,LL>
using namespace std;
const int mn=3e5+6;
int fa[mn],n,id[mn],siz[mn],top;
LL ans;
vector<int> to[mn];
vector<LL> tmp;
priority_queue<LL,vector<LL>,less<LL>> q[mn];
struct node {
int l,r,w;
bool operator< (const node &a) const {
if(a.l==l) return r>a.r;
else return l<a.l;
}
}d[mn];
void dfs(int x)
{
int mx=0,son=0;
for(int t:to[x]) {
dfs(t);
if(siz[t]>mx) mx=siz[t],son=t;
}
id[x]=id[son];
for(int t:to[x]) if(t!=son) {
while(!q[id[t]].empty()) {
tmp.pb(q[id[x]].top()+q[id[t]].top());
q[id[x]].pop();q[id[t]].pop();
}
for(auto it:tmp) q[id[x]].push(it);
tmp.clear();
}
if(!id[x]) id[x]=++top;
q[id[x]].push(d[x].w);
siz[x]=q[id[x]].size();
}
int main()
{
int tests=1;//scanf("%d",&tests);
while(tests--) {
scanf("%d",&n);
d[n+1].l=0,d[n+1].r=1000000,d[n+1].w=0;
for(int i=1;i<=n;++i) {scanf("%d%d%d",&d[i].l,&d[i].r,&d[i].w);d[i].r--;}
sort(d+1,d+n+2);
int las=1;
for(int i=2;i<=n+1;++i) {
while(d[las].r<d[i].r) {las=fa[las];}
to[las].pb(i);
fa[i]=las;las=i;
}
// for(int i=1;i<=n+1;++i) cout<<d[i].l<<" "<<d[i].r<<endl;
// cout<<endl<<endl<<endl;
// for(int i=2;i<=n+1;++i) cout<<i<<" "<<fa[i]<<endl;
dfs(1);
for(int i=1;i<=n;++i) {
if(!q[id[1]].empty()) {ans=ans+q[id[1]].top();q[id[1]].pop();}
printf("%lld ",ans);
}
}
return 0;
}
i Minimum Diameter Spanning Tree
题意
最小直径生成树板题,要求输出最小直径生成树。
首先我们考虑绝对中心的概念,它可以存在于任何一条边上,并且这个点到所有点的最短距离的最大值最小。我们可以证明,绝对中心到直径两个端点距离相同。
我们枚举每一条边,假设绝对中心在这条边上,那么中心到某个点的最短距离可以表示为\(\min(d[u][s] + x , d[v][s] + L - x)\),画出函数图像来的话就是一条折线。在这条折线上取一个最小值就是中心到s的最短距离的最小值,那到每个点都是这样一条折线,由于要取最短距离的最大值,所以我们的点得在所有折线构成的最上方的折线上取一个最低点。
我们可以预处理出每两点之间的距离,然后利用类似单调队列的方式更新答案。复杂度\(O(n^3)\)。
最后求最小直径生成树的时候,绝对中心边上的两点\(dis\)设为真实值,跑spfa更新答案就可以。
#include <bits/stdc++.h>
#define LL long long
#define pb push_back
#define mp make_pair
#define pii pair<int,int>
#define fi first
#define se second
#define lc nd<<1
#define rc nd<<1|1
#define lowbit(x) (x&(-x))
#define pLL pair<LL,LL>
using namespace std;
const int mn=500+6;
LL d[mn][mn],ans;
double dis[mn];
int rk[mn][mn],n,m,s1,s2,pre[mn],vis[mn],W[mn][mn];
queue<int> q;
struct edge {
int u,v,w;
}e[mn*mn];
int main()
{
int tests=1;//scanf("%d",&tests);
while(tests--) {
memset(d,63,sizeof d);
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i) d[i][i]=0;
for(int i=1;i<=m;++i) {
scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
d[e[i].u][e[i].v]=d[e[i].v][e[i].u]=e[i].w;
W[e[i].u][e[i].v]=W[e[i].v][e[i].u]=e[i].w;
}
for(int k=1;k<=n;++k)
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j) {
if(d[i][j]>d[i][k]+d[k][j]) d[i][j]=d[i][k]+d[k][j];
}
for(int i=1;i<=n;++i) {
for(int j=1;j<=n;++j) rk[i][j]=j;
sort(rk[i]+1,rk[i]+n+1,[&](int a, int b) {
return d[i][a] < d[i][b];
});
}
ans=1e16;
for(int i=1;i<=m;++i) {
int u=e[i].u,v=e[i].v;
if((d[u][rk[u][n]]<<1)<ans) ans=d[u][rk[u][n]]<<1,s1=s2=u,dis[s1]=0;
if((d[v][rk[v][n]]<<1)<ans) ans=d[v][rk[v][n]]<<1,s1=s2=v,dis[s1]=0;
for(int las=n,j=n-1;j;--j) {
if(d[v][rk[u][j]]>d[v][rk[u][las]]) {
if(d[u][rk[u][j]]+d[v][rk[u][las]]+e[i].w<ans) {
ans=d[u][rk[u][j]]+d[v][rk[u][las]]+e[i].w,s1=u,s2=v;
dis[s1]=(double)ans/2.0-d[u][rk[u][j]];
dis[s2]=(double)d[u][v]-dis[s1];
}
las=j;
}
}
}
printf("%lld\n",ans);
for(int i=1;i<=n;++i) if(i!=s1&&i!=s2) dis[i]=1e18;
q.push(s1);
if(s1!=s2) q.push(s2),pre[s2]=s1;
while(!q.empty()) {
int now=q.front();q.pop();vis[now]=0;
for(int i=1;i<=n;++i) if(W[now][i]) {
if(dis[now]+d[now][i]<dis[i]) {
dis[i]=dis[now]+W[now][i];
pre[i]=now;
if(!vis[i]) {
q.push(i);
vis[i]=1;
}
}
}
}
for(int i=1;i<=n;++i) {
if(pre[i]) printf("%d %d\n",i,pre[i]);
}
}
return 0;
}

浙公网安备 33010602011771号