Codeforces 1263F Economic Difficulties dp

题意

给你两棵 n n 个点的树,一个是从上到下的,一个是从下到上的,最后末尾都有n个叶子结点,分别连向机器,现在你要删除尽量多的边,使得每个机器都和至少一个树的树根相连。且保证树上的点连机器的边是不交叉的
n 1000 n \leq 1000

分析

树上的点连机器的边是不交叉的,肯定一个结点子树能够连到的机器是连续的一段区间
保证了肯定有一个点使得这个区间覆盖的值最大,就把这些区间变成区间覆盖就好了,时间复杂度是 O ( n ) O(n)

当然了,如果树上的点连机器的边是交叉的话,每个节点虽然覆盖了整个区间,但是值未必合法(可能只覆盖了区间内其中几个),那该怎么办呢

其实可以进行问题的转化,不把一个子树看在一起,把每条边单独看,每个点有一个区间,删除来当前点的边贡献加1(根节点除外),有N个可重复贡献的区间,求出在每个询问区间内的贡献最大值

就是按照右端点排序,然后dp, d p [ i ] [ j ] dp[i][j] 表示 i i j j 这个区间的所有机器都不连所丢弃的最多的边
d p [ i ] [ j ] = d p [ i ] [ j 1 ] + [ m x [ k ] = j ] [ m n [ k ] i ] dp[i][j] = dp[i][j-1] + [mx[k] = j][mn[k] \geq i]
这样dp就把一个个右端点在这个区间内的贡献都算到了

时间是 O ( n 2 ) O(n^2)

代码

O ( N ) O(N)

#include <bits/stdc++.h>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/assoc_container.hpp>
#define pb push_back
#define MP make_pair
#define fi first
#define se second
 
using namespace __gnu_pbds;
using namespace std;
 
typedef long long ll;
typedef pair<int,int> pii;
typedef tree<int,null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update> splay;
 
const int N = 2010;
const int mod = 998244353;
const int inf = 1e9;
 
inline int read()
{
  int p=0; int f=1; char ch=getchar();
  while(ch<'0' || ch>'9'){if(ch=='-') f=-1; ch=getchar();}
  while(ch>='0' && ch<='9'){p=p*10+ch-'0'; ch=getchar();}
  return p*f;
}

struct node{int l,r,d;}p[N<<1]; int plen = 0;

int ida[N],idb[N]; vector<int> ea[N],eb[N],va[N],vb[N];
int fa[N][N],fb[N][N],dp[N]; int mna[N],mxa[N],mnb[N],mxb[N],siz[N];
void dfs1(int x)
{
  mna[x] = inf; mxa[x] = -inf; siz[x] = 1;
  for(auto y:ea[x])
  {
    dfs1(y);
    siz[x] += siz[y];
	mna[x] = min(mna[x] , mna[y]);
    mxa[x] = max(mxa[x] , mxa[y]);
  }if(ida[x]) mna[x] = mxa[x] = ida[x];
  if(x==1) siz[x] --; p[++plen] = {mna[x] , mxa[x] , siz[x]};
}
void dfs2(int x)
{
  mnb[x] = inf; mxb[x] = -inf; siz[x] = 1;
  for(auto y:eb[x])
  {
    dfs2(y);
    siz[x] += siz[y];
    mnb[x] = min(mnb[x] , mnb[y]);
    mxb[x] = max(mxb[x] , mxb[y]);
  }if(idb[x]) mnb[x] = mxb[x] = idb[x];
  if(x==1) siz[x] --; p[++plen] = {mnb[x] , mxb[x] , siz[x]};
}

bool cmp(const node &x,const node &y){return x.r < y.r;}

int main()
{
  int n = read();
  int a = read();
  for(int i=2;i<=a;i++) ea[read()].pb(i);
  for(int i=1;i<=n;i++) ida[read()] = i;
  int b = read();
  for(int i=2;i<=b;i++) eb[read()].pb(i);
  for(int i=1;i<=n;i++) idb[read()] = i;
  dfs1(1); dfs2(1);
  sort(p+1,p+plen+1,cmp);
  for(int i=1;i<=plen;i++) dp[p[i].r] = max(dp[p[i].r] , dp[p[i].l-1] + p[i].d);
//  for(int i=1;i<=plen;i++) printf("%d %d : %d\n",p[i].l,p[i].r,p[i].d);
//  for(int i=1;i<=n;i++) printf("%d ",dp[i]); printf("\n");
  return printf("%d\n",dp[n]),0;
}

O ( N 2 ) O(N^2)

#include <bits/stdc++.h>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/assoc_container.hpp>
#define pb push_back
#define MP make_pair
#define fi first
#define se second
 
using namespace __gnu_pbds;
using namespace std;
 
typedef long long ll;
typedef pair<int,int> pii;
typedef tree<int,null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update> splay;
 
const int N = 2010;
const int mod = 998244353;
const int inf = 1e9;
 
inline int read()
{
  int p=0; int f=1; char ch=getchar();
  while(ch<'0' || ch>'9'){if(ch=='-') f=-1; ch=getchar();}
  while(ch>='0' && ch<='9'){p=p*10+ch-'0'; ch=getchar();}
  return p*f;
}

int ida[N],idb[N]; vector<int> ea[N],eb[N],va[N],vb[N];
int fa[N][N],fb[N][N],dp[N]; int mna[N],mxa[N],mnb[N],mxb[N];
void dfs1(int x)
{
  mna[x] = inf; mxa[x] = -inf;
  for(auto y:ea[x])
  {
    dfs1(y);
    mna[x] = min(mna[x] , mna[y]);
    mxa[x] = max(mxa[x] , mxa[y]);
  }if(ida[x]) mna[x] = mxa[x] = ida[x];
  if(x!=1) va[mxa[x]].pb(mna[x]);
}
void dfs2(int x)
{
  mnb[x] = inf; mxb[x] = -inf;
  for(auto y:eb[x])
  {
    dfs2(y);
    mnb[x] = min(mnb[x] , mnb[y]);
    mxb[x] = max(mxb[x] , mxb[y]);
  }if(idb[x]) mnb[x] = mxb[x] = idb[x];
  if(x!=1) vb[mxb[x]].pb(mnb[x]);
}

int main()
{
  int n = read();
  int a = read();
  for(int i=2;i<=a;i++) ea[read()].pb(i);
  for(int i=1;i<=n;i++) ida[read()] = i;
  int b = read();
  for(int i=2;i<=b;i++) eb[read()].pb(i);
  for(int i=1;i<=n;i++) idb[read()] = i;
  dfs1(1); dfs2(1);
  
  memset(fa,0,sizeof(fa));
  memset(fb,0,sizeof(fb));
  
//  for(int i=1;i<=n;i++){printf("%d:",i); for(auto k:va[i]) printf(" %d",k); printf("\n");}
//  for(int i=1;i<=n;i++){printf("%d:",i); for(auto k:vb[i]) printf(" %d",k); printf("\n");}
  
  
  for(int i=1;i<=n;i++) for(int j=i;j<=n;j++)
  {
    fa[i][j] = fa[i][j-1]; fb[i][j] = fb[i][j-1];
    for(auto k:va[j]) fa[i][j] += (k>=i);
    for(auto k:vb[j]) fb[i][j] += (k>=i);
  }
  
  memset(dp,0,sizeof(dp));
  for(int i=1;i<=n;i++) for(int j=0;j<i;j++) dp[i] = max(dp[i] , dp[j] + max(fa[j+1][i] , fb[j+1][i]) );
  
  
  return printf("%d\n",dp[n]),0;
}

猜你喜欢

转载自blog.csdn.net/weixin_39708759/article/details/103352197