看到“单组询问且没有额外限制”,那么就可以发现用一个树形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;
}