保卫王国

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
看到“单组询问且没有额外限制”,那么就可以发现用一个树形dp来解决,设dp[u][0/1]表示 u这个子 树,u这个点选或者不选的最小代价。转移的时候考虑u这个点选或者不选,以及儿子选或者不选即可。这个时间复杂度是o(nm)只有44分

68分的算法,就是在44分的算法上可以加一个特判,当情况等于A,
,这个时候我们可以用线段树来解决,对每个区间 [l,r],维护l这个点选或者不 选,r这个点选或者不选四种情况的最小代价,合并的时候需要枚举一下中间这个点的选法。每次我们限制了一组 点 x,y(x<y),那么我们只要分别求出[1,x][x,y],[y,n]的答案,然后在合并。

对于这条链,我们要求相邻的点 至少有一个被选中,所以对这些点跑一个动态规划。注意到这个树形dp记录的信息是可以减的,所以对于一个 点的额外代价就相当于把它的所有邻居的信息加起来然后减去链上的两个邻居就行了。以额外获得B和2子任务的分数,80分。

100分就是先把上面的都综合一下,然后这里就变成了树上链加的操作,我们可以用倍增解决,记info[u][k]表示将u往上走 2 k 2^k 2k步的信息合并起来的结果,递推一下就行了。
在树上进行倍增像倍增LCA一样

我当时想到了倍增,应为这题和BZOJ4034有点像,当时想得是,用倍增求出所有可能,在暴力枚举看那种代价最小,但没打出来(23333。

44分

#include<bits/stdc++.h>
#define ll long long
using namespace std;
template <class T>inline void read(T &x)
{
 x=0;
 int ne=0;
 char c;
 while(!isdigit(c=getchar()))
  ne=c=='-';
 x=c-48;
 while(isdigit(c=getchar()))
  x=(x<<3)+(x<<1)+c-48;
 x=ne?-x:x;
 return ;
}
const int maxn=200005;
const ll inf=1e16;
struct Edge
{
 int ne,to;
}edge[maxn<<1];
char opt[5];
int n,m,p[maxn];
int h[maxn],num_edge=1;
inline void add_edge(int f,int to)
{
 edge[++num_edge].ne=h[f];
 edge[num_edge].to=to;
 h[f]=num_edge;
}
namespace bf
{
 ll f[maxn][2];
 void dp(int now,int fa)
 {
  int v;
  if(f[now][0]!=inf)
   f[now][0]=0;
  if(f[now][1]!=inf)
   f[now][1]=0;
  for(register int i=h[now];i;i=edge[i].ne)
  {
   v=edge[i].to;
   if(v==fa)
    continue;
   dp(v,now);
   f[now][0]+=f[v][1];
   f[now][1]+=min(f[v][0],f[v][1]);
  }
  f[now][1]+=p[now];
  return ;
 }
 void main()
 {
  int a,x,b,y;
  ll tmp=0;
  while(m--)
  {
   tmp=0;
   read(a),read(x),read(b),read(y);
            memset(f,0,sizeof(f));
   if(x==1)
    f[a][0]=inf;
   else 
    f[a][1]=inf;
   if(y==1)
    f[b][0]=inf;
   else 
    f[b][1]=inf;
   dp(1,0);
   if(f[1][0]>=inf&&f[1][1]>=inf)
    puts("-1");
   else 
    printf("%lld\n",min(f[1][0],f[1][1]));
  }
  return ;
 }
}
int main(){
 int x,y;
 read(n),read(m);
 scanf("%s",opt);
 for(register int i=1;i<=n;i++)
  read(p[i]);
 for(register int i=1;i<n;i++)
 {
  read(x),read(y);
  add_edge(x,y);
  add_edge(y,x);
 }
 if(n<=2000&&m<=2000)
  bf::main();
 else 
  bf::main();
 return 0;
}

68分

#include<iostream>
#include<cstdio>
#include<cstring>
#include<set>
#include<cstdlib>
#include<algorithm>
#include<map>
#include<queue>
#include<vector>
#include<cmath>
#define maxn 100010
#define ll long long
#define inf (1e15)
using namespace std;
int n,m,la[maxn],tot;ll p0[maxn],p[maxn],dp[maxn][2];
char tpe[10];
struct edge{int v,ne;}e[maxn<<1];
inline void add(int u,int v){
 e[tot].v=v,e[tot].ne=la[u],la[u]=tot++;
}
void init(){
 tot=0;memset(la,-1,sizeof(la));
 scanf("%d%d",&n,&m);scanf("%s",tpe);
 for(int i=1;i<=n;++i)scanf("%lld",&p[i]);
 for(int i=2;i<=n;++i){
  int u,v;scanf("%d%d",&u,&v);
  add(u,v),add(v,u);
 }
}
namespace subtask1{
 inline void dfs(int u,int fa){
  dp[u][0]=p0[u],dp[u][1]=p[u];
  for(int i=la[u];~i;i=e[i].ne){
   int v=e[i].v;
   if(v==fa)continue;
   dfs(v,u);
   dp[u][0]+=dp[v][1];
   dp[u][1]+=min(dp[v][0],dp[v][1]);
  }
 }
 void solve(){
  memset(p0,0,sizeof(p0));
  while(m--){
   int a,x,b,y,t1,t2;
   scanf("%d%d%d%d",&a,&x,&b,&y);
   if(x)p0[a]=inf;
   else t1=p[a],p[a]=inf;
   if(y)p0[b]=inf;
   else t2=p[b],p[b]=inf;
   dfs(1,0);
   ll ans=min(dp[1][0],dp[1][1]);
   if(ans>=inf)puts("-1");
   else printf("%lld\n",ans);
   if(x)p0[a]=0;
   else p[a]=t1;
   if(y)p0[b]=0;
   else p[b]=t2;
  }
 }
}
namespace subtask2{
 struct segment_tree{ll ans,v1,v2,v3,v4;}t[maxn<<2];//v1:00 v2:11 v3:10 v4:01
 inline void pushup(int o,int l,int r){
  int ls=o<<1,rs=o<<1|1,mid=(l+r)>>1;
  t[o].v1=t[ls].v4+t[rs].v3;
 // if(mid-l+1>2||mid-l+1==1)
  t[o].v1=min(t[o].v1,t[ls].v1+t[rs].v3);
//  if(r-mid>2||r-mid==1)
  t[o].v1=min(t[o].v1,t[ls].v4+t[rs].v1);
  t[o].v2=t[ls].v2+t[rs].v2;
  t[o].v2=min(t[o].v2,t[ls].v3+t[rs].v2);
  t[o].v2=min(t[o].v2,t[ls].v2+t[rs].v4);
  t[o].v3=t[ls].v2+t[rs].v3;
  t[o].v3=min(t[o].v3,t[ls].v3+t[rs].v3);
  t[o].v3=min(t[o].v3,t[ls].v2+t[rs].v1);
 // if(o==1)cerr<<t[o].v2<<" "<<t[ls].v3<<" "<<mid<<endl;
  t[o].v4=t[ls].v4+t[rs].v2;
  t[o].v4=min(t[o].v4,t[ls].v4+t[rs].v4);
  t[o].v4=min(t[o].v4,t[ls].v1+t[rs].v2);
  t[o].ans=min(min(t[o].v1,t[o].v2),min(t[o].v3,t[o].v4));
 }
 inline void build(int o,int l,int r){//cerr<<o<<" "<<l<<r<<endl;
  if(l==r){
   t[o].v1=p0[l],t[o].v2=p[l],t[o].v3=t[o].v4=inf;
   t[o].ans=min(min(t[o].v1,t[o].v2),min(t[o].v3,t[o].v4));
   return;
  }
  int mid=(l+r)>>1;
  build(o<<1,l,mid),build(o<<1|1,mid+1,r);
  pushup(o,l,r);//cerr<<t[o].ans<<endl;
 }
 inline void update(int o,int l,int r,int pos){
  if(l==r){
   t[o].v1=p0[l],t[o].v2=p[l],t[o].v3=t[o].v4=inf;
   t[o].ans=min(min(t[o].v1,t[o].v2),min(t[o].v3,t[o].v4));
   return;
  }
  int mid=(l+r)>>1;
  if(pos<=mid)update(o<<1,l,mid,pos);
  else update(o<<1|1,mid+1,r,pos);
  pushup(o,l,r);
 }
 void solve(){
  memset(p0,0,sizeof(p0));//cerr<<n<<endl;
  build(1,1,n);
  while(m--){
   int a,x,b,y,t1,t2;
   scanf("%d%d%d%d",&a,&x,&b,&y);
   if(x)p0[a]=inf;
   else t1=p[a],p[a]=inf;
   update(1,1,n,a);
   if(y)p0[b]=inf;
   else t2=p[b],p[b]=inf;
   update(1,1,n,b);
   if(t[1].ans>=inf)puts("-1");
   else printf("%lld\n",t[1].ans);
   if(x)p0[a]=0;
   else p[a]=t1;
   update(1,1,n,a);
   if(y)p0[b]=0;
   else p[b]=t2;
   update(1,1,n,b);
  }
 }
}
void solve(){
 if(n<=2000&&m<=2000){subtask1::solve();return;}
 subtask2::solve();
}
int main(){
 init();
 solve();
 return 0;
}

80分

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+7;
int n,m,tp[maxn],p[maxn],fa[maxn];
ll f[maxn][2],g[maxn][2];
vector<int>edge[maxn];
char typ[3];
void dp(int u,int ff)
{
 f[u][0]=0;
 f[u][1]=p[u];
 for(int i=0;i<(int)edge[u].size();i++)
 {
  if(edge[u][i]!=ff)
  {
   dp(edge[u][i],u);
   f[u][0]+=f[edge[u][i]][1];
   if(f[u][0]>1e17)
    f[u][0]=1e17;
   f[u][1]+=min(f[edge[u][i]][0],f[edge[u][i]][1]);
   if(f[u][1]>1e17)
    f[u][1]=1e17;
  }
 }
 if(!tp[u])
  f[u][1]=1e17;
 if(tp[u]==1)
  f[u][0]=1e17;
}
void dfs(int u)
{
 for(int i=0;i<(int)edge[u].size();i++)
  if(edge[u][i]!=fa[u])
   fa[edge[u][i]]=u,dfs(edge[u][i]);
}
void modify(int u,int son)
{
 g[u][0]=f[u][0],g[u][1]=f[u][1];
 if(g[u][0]!=1e17)
 {
  g[u][0]-=f[son][1];
  g[u][0]+=g[son][1];
  if(g[u][0]>1e17)
   g[u][0]=1e17;
 }
 if(g[u][1]!=1e17)
 {
  g[u][1]-=min(f[son][0],f[son][1]);
  g[u][1]+=min(g[son][0],g[son][1]);
  if(g[u][1]>1e17)
   g[u][1]=1e17;
 }
 if(u!=1)
  modify(fa[u],u);
}
int main()
{
 scanf("%d%d%s",&n,&m,typ);
 for(int i=1;i<=n;i++)
  scanf("%d",&p[i]);
 if(n<=2000&&m<=2000)
 {
  memset(tp,-1,sizeof tp);
  for(int i=1,x,y;i<n;i++)
   scanf("%d%d",&x,&y),edge[x].push_back(y),edge[y].push_back(x);
  while(m--)
  {
   int a,x,b,y;
   scanf("%d%d%d%d",&a,&x,&b,&y);
   tp[a]=x,tp[b]=y;
   dp(1,0);
   tp[a]=tp[b]=-1;
   ll ans=min(f[1][0],f[1][1]);
   if(ans==1e17)
    puts("-1");
   else 
    printf("%lld\n",ans);
  }
  return 0;
 }
 if((typ[0]=='B'||typ[0]=='C')&&typ[1]=='1')
 {
  for(int i=1,x,y;i<n;i++)
   scanf("%d%d",&x,&y),edge[x].push_back(y),edge[y].push_back(x);
  dfs(1);
  memset(tp,-1,sizeof tp);
  dp(1,0);
  while(m--)
  {
   int b,y;
   scanf("%*d%*d%d%d",&b,&y);
   g[b][y]=f[b][y];
   g[b][y^1]=1e17;
   if(b!=1)
    modify(fa[b],b);
   if(g[1][1]==1e17)
    puts("-1");
   else 
    printf("%lld\n",g[1][1]);
  }
  return 0;
 }
 if(typ[0]=='A')
  for(int i=1;i<n;i++)
   scanf("%*d%*d");
 if(typ[0]=='A'&&typ[1]=='1')
 {
  f[n][0]=0,f[n][1]=p[n];
  for(int i=n-1;i;i--)
   f[i][0]=f[i+1][1],f[i][1]=min(f[i+1][0],f[i+1][1])+p[i];
  g[1][0]=1e17,g[1][1]=p[1];
  for(int i=2;i<=n;i++)
   g[i][0]=g[i-1][1],g[i][1]=min(g[i-1][0],g[i-1][1])+p[i];
  while(m--)
  {
   int b,y;
   scanf("%*d%*d%d%d",&b,&y);
   ll ans;
   if(!y)
    ans=f[b+1][1]+g[b-1][1];
   else 
    ans=min(f[b+1][0],f[b+1][1])+min(g[b-1][0],g[b-1][1])+p[b];
   printf("%lld\n",ans);
  }
  return 0;
 }
 if(typ[0]=='A'&&typ[1]=='2')
 {
  f[n][0]=0,f[n][1]=p[n];
  for(int i=n-1;i;i--)
   f[i][0]=f[i+1][1],f[i][1]=min(f[i+1][0],f[i+1][1])+p[i];
  g[1][0]=0,g[1][1]=p[1];
  for(int i=2;i<=n;i++)
   g[i][0]=g[i-1][1],g[i][1]=min(g[i-1][0],g[i-1][1])+p[i];
  while(m--)
  {
   int a,x,b,y;
   scanf("%d%d%d%d",&a,&x,&b,&y);
   if(a>b)
    swap(a,b),swap(x,y);
   if(!x&&!y)
   {
    puts("-1");
    continue;
   }
   ll ans=f[b][y]+g[a][x];
   printf("%lld\n",ans);
  }
  return 0;
 }
 while(m--)
  puts("-1");
 return 0;
}

100分

#include<bits/stdc++.h>
#define mxn 100010
using namespace std;
typedef long long LL;
char typ[10];const LL inf=1ll<<60;
int n,m,q,x,y,xx,yy,z,head[mxn],dep[mxn],p[mxn][21];
LL f[mxn][2],g[mxn][2],h[mxn][21][4],a[4],b[4],c[4],ans[4];
struct ed{int to,nxt;}edge[mxn<<1];
void addedge(int u,int v){
 edge[++m]=(ed){v,head[u]},head[u]=m;
 edge[++m]=(ed){u,head[v]},head[v]=m;
}
void dfs1(int u,int fa){
 for (int i=head[u],v;i;i=edge[i].nxt)
  if ((v=edge[i].to)!=fa) dfs1(v,u),f[u][1]+=min(f[v][0],f[v][1]),f[u][0]+=f[v][1];
}
void dfs2(int u,int fa,int d){
 for (int i=head[u],v;i;i=edge[i].nxt)
  if ((v=edge[i].to)!=fa)
   g[v][0]=g[u][1]+f[u][1]-min(f[v][0],f[v][1]),
   g[v][1]=min(g[u][0]+f[u][0]-f[v][1],g[v][0]),dfs2(v,u,d+1);
 for (int i=head[u],v;i;i=edge[i].nxt)
  if ((v=edge[i].to)!=fa) h[v][0][3]=f[u][1]-min(f[v][0],f[v][1]),h[v][0][0]=f[u][0]-f[v][1];
 p[u][0]=fa,dep[u]=d;
}
int lca(int x,int y){
 if (dep[x]<dep[y]) {int t=x;x=y;y=t;}
 for (int i=20;i>=0;--i)
  if (dep[x]-(1<<i)>=dep[y]) x=p[x][i];
 if (x==y) return x;
 for (int i=20;i>=0;--i)
  if (p[x][i]!=p[y][i]) x=p[x][i],y=p[y][i];
 return p[x][0];
}
void merge(LL x[],LL y[],LL z[]){
 z[0]=min(x[0]+y[1],min(x[2]+y[0],x[2]+y[1])),z[1]=min(x[1]+y[1],min(x[3]+y[0],x[3]+y[1])),
 z[2]=min(x[0]+y[3],min(x[2]+y[2],x[2]+y[3])),z[3]=min(x[1]+y[3],min(x[3]+y[2],x[3]+y[3]));
}
int main()
{
 memset(h,0x3f,sizeof(h));
 scanf("%d%d%s",&n,&q,typ);
 for (int i=1;i<=n;++i) scanf("%lld",&f[i][1]);
 for (int i=1;i<n;++i) scanf("%d%d",&x,&y),addedge(x,y);
 dfs1(1,1),dfs2(1,1,1);
 for (int j=1;j<=20;++j)
  for (int i=1;i<=n;p[i][j]=p[p[i][j-1]][j-1],++i) merge(h[i][j-1],h[p[i][j-1]][j-1],h[i][j]);
 for (int j=1;j<=q;++j){
  scanf("%d%d%d%d",&x,&xx,&y,&yy),z=lca(x,y);
  if (x==z||y==z){
   c[1]=c[2]=c[3]=c[0]=a[1]=a[2]=a[3]=a[0]=inf;
   if (x==z) x=y;
   if ((y==z&&xx)||(y!=z&&yy)) a[3]=f[x][1];
   else a[0]=f[x][0];
   for (int i=20;i>=0;--i)
    if (dep[x]-(1<<i)>dep[z])
     merge(a,h[x][i],ans),x=p[x][i],a[0]=ans[0],a[1]=ans[1],a[2]=ans[2],a[3]=ans[3];
   if ((y==z&&yy)||(y!=z&&xx)) c[3]=f[z][1]-min(f[x][0],f[x][1])+g[z][1];
   else c[0]=f[z][0]-f[x][1]+g[z][0];
   merge(a,c,ans);
  }
  else{
   a[1]=a[2]=a[3]=a[0]=b[1]=b[2]=b[3]=b[0]=c[1]=c[2]=inf;
   if (xx) a[3]=f[x][1]; else a[0]=f[x][0];
   if (yy) b[3]=f[y][1]; else b[0]=f[y][0];
   for (int i=20;i>=0;--i)
    if (dep[x]-(1<<i)>dep[z])
     merge(a,h[x][i],ans),x=p[x][i],a[0]=ans[0],a[1]=ans[1],a[2]=ans[2],a[3]=ans[3];
   for (int i=20;i>=0;--i)
    if (dep[y]-(1<<i)>dep[z])
     merge(b,h[y][i],ans),y=p[y][i],b[0]=ans[0],b[1]=ans[1],b[2]=ans[2],b[3]=ans[3];
   c[0]=f[z][0]-f[x][1]-f[y][1]+g[z][0];
   c[3]=f[z][1]-min(f[x][0],f[x][1])-min(f[y][0],f[y][1])+g[z][1];
   merge(a,c,ans),a[0]=ans[0],a[1]=ans[1],a[2]=ans[2],a[3]=ans[3];
   ans[0]=min(a[0]+b[2],min(a[2]+b[0],a[2]+b[2])),ans[1]=min(a[1]+b[2],min(a[3]+b[0],a[3]+b[2]));
   ans[2]=min(a[0]+b[3],min(a[2]+b[1],a[2]+b[3])),ans[3]=min(a[1]+b[3],min(a[3]+b[1],a[3]+b[3]));
  }
  LL anss=min(min(ans[0],ans[1]),min(ans[2],ans[3]));printf("%lld\n",anss>=inf?-1ll:anss);
 }
 return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值