NC21475. [NOIP2018]保卫王国
描述
输入描述
第 1 行包含两个正整数𝑛, 𝑚和一个字符串𝑡𝑦𝑝𝑒,分别表示城市数、要求数和数据类 型。𝑡𝑦𝑝𝑒是一个由大写字母 A,B 或 C 和一个数字 1,2,3 组成的字符串。它可以帮助 你获得部分分。你可能不需要用到这个参数。这个参数的含义在【数据规模与约定】中 有具体的描述。
第2行n个整数pi,表示编号i的城市中驻扎军队的花费。
接下来n − 1行,每行两个正整数u, v,表示有一条u到v的双向道路。 接下来m行,第j行四个整数a, x, b, y(a ≠ b),表示第j个要求是在城市a驻扎x支军队,
在城市b驻扎y支军队。其中,x 、 y 的取值只有 0 或 1:若 x 为 0,表示城市 a 不得驻 扎军队,若 x 为 1,表示城市 a 必须驻扎军队;若 y 为 0,表示城市 b 不得驻扎军队, 若 y 为 1,表示城市 b 必须驻扎军队。 输入文件中每一行相邻的两个数据之间均用一个空格分隔。
输出描述
输出共m行,每行包含 1 个整数,第j行表示在满足国王第j个要求时的最小开销, 如果无法满足国王的第j个要求,则该行输出-1。
示例1
输入:
5 3 C3 2 4 1 3 9 1 5 5 2 5 3 3 4 1 0 3 0 2 1 3 1 1 0 5 0
输出:
12 7 -1
说明:
对于第一个要求,在 4 号和 5 号城市驻扎军队时开销最小。C++14(g++5.4) 解法, 执行用时: 1319ms, 内存消耗: 21400K, 提交时间: 2019-11-15 15:10:43
#include<cstdio> #include<cstring> #include<algorithm> #define N 100005 #define inf (1ll<<50) #define ll long long using namespace std; int n,m,t; int first[N],v[N<<1],nxt[N<<1]; int fa[N],Fa[N],son[N][2]; ll A[N],f[N][2]; void add(int x,int y){ nxt[++t]=first[x],first[x]=t,v[t]=y; } struct matrix{ ll m[2][2]; matrix() {m[0][0]=m[0][1]=m[1][0]=m[1][1]=inf;} friend matrix operator*(const matrix &A,const matrix &B){ matrix C; for(int i=0;i<2;++i) for(int k=0;k<2;++k) for(int j=0;j<2;++j) C.m[i][j]=min(C.m[i][j],A.m[i][k]+B.m[k][j]); return C; } }val[N],T[N]; void dp(int x){ f[x][1]=A[x],f[x][0]=0; for(int i=first[x];i;i=nxt[i]){ int to=v[i]; if(to==fa[x]) continue; fa[to]=Fa[to]=x,dp(to); f[x][1]+=min(f[to][0],f[to][1]); f[x][0]+=f[to][1]; } val[x].m[1][0]=f[x][0]; val[x].m[0][0]=val[x].m[0][1]=f[x][1]; T[x]=val[x]; } namespace LCT{ bool Get(int x) {return son[fa[x]][1]==x;} bool isroot(int x) {return (!fa[x])||(son[fa[x]][0]!=x&&son[fa[x]][1]!=x);} void update(int x){ T[x]=val[x]; if(son[x][0]) T[x]=T[son[x][0]]*T[x]; if(son[x][1]) T[x]=T[x]*T[son[x][1]]; } void Rotate(int x){ int y=fa[x],z=fa[y]; int k=Get(x),l=son[x][k^1]; son[y][k]=l,fa[l]=(l?y:0); if(!isroot(y)) son[z][Get(y)]=x;fa[x]=z; son[x][k^1]=y,fa[y]=x; update(y),update(x); } void Splay(int x){ while(!isroot(x)){ int y=fa[x]; if(!isroot(y)) Rotate(Get(x)==Get(y)?y:x); Rotate(x); } } void Access(int x){ for(int i=0;x;x=fa[i=x]){ Splay(x); if(son[x][1]){ val[x].m[1][0]+=T[son[x][1]].m[0][0]; val[x].m[0][0]+=min(T[son[x][1]].m[0][0],T[son[x][1]].m[1][0]); } if(i){ val[x].m[1][0]-=T[i].m[0][0]; val[x].m[0][0]-=min(T[i].m[0][0],T[i].m[1][0]); } val[x].m[0][1]=val[x].m[0][0]; son[x][1]=i,update(x); } } void Modify(int x,ll y){ Access(x),Splay(x); val[x].m[0][0]+=y,val[x].m[0][1]+=y; update(x); } ll Query(){ Splay(1); return min(T[1].m[0][0],T[1].m[1][0]); } } using namespace LCT; char S[5]; void solve(int u,int x,int v,int y){ if(!x&&!y&&(Fa[u]==v||Fa[v]==u)) {puts("-1");return;} Modify(u,x?-inf:inf),Modify(v,y?-inf:inf); printf("%lld\n",Query()+inf*(x+y)); Modify(u,x?inf:-inf),Modify(v,y?inf:-inf); } int main(){ int x,y,a,b; scanf("%d%d%s",&n,&m,S); for(int i=1;i<=n;++i) scanf("%d",&A[i]); for(int i=1;i<n;++i){ scanf("%d%d",&x,&y); add(x,y),add(y,x); } dp(1); while(m--){ scanf("%d%d%d%d",&a,&x,&b,&y),solve(a,x,b,y); } return 0; }
C++ 解法, 执行用时: 499ms, 内存消耗: 17916K, 提交时间: 2022-04-23 10:17:26
#include<bits/stdc++.h> using namespace std; const long long NN=100004,INF=1e15; struct node { long long a,b,c,d; node(){} node(const long long &_a,const long long &_b,const long long &_c,const long long &_d){a=_a,b=_b,c=_c,d=_d;} }f[NN],g[NN]; node operator*(const node&a,const node&b) { return node(max(a.a+b.a,a.b+b.c),max(a.a+b.b,a.b+b.d),max(a.c+b.a,a.d+b.c),max(a.c+b.b,a.d+b.d)); } int ch[NN][2],fa[NN],e[NN],dis[NN<<1],nxt[NN<<1],tot; long long dp[NN][2],w[NN]; void add(int a,int b) { nxt[++tot]=e[a]; e[a]=tot; dis[tot]=b; } void dfs(int x) { dp[x][1]=w[x]; for(int i=e[x];i;i=nxt[i]) { if(fa[x]==dis[i]) continue; fa[dis[i]]=x; dfs(dis[i]); dp[x][1]+=dp[dis[i]][0]; dp[x][0]+=max(dp[dis[i]][0],dp[dis[i]][1]); } f[x]=g[x]=node(dp[x][0],dp[x][0],dp[x][1],-INF); } bool in(int x) { return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x; } void up(int x) { f[x]=g[x]; if(ch[x][0]) f[x]=f[ch[x][0]]*f[x]; if(ch[x][1]) f[x]=f[x]*f[ch[x][1]]; } void rotate(int x) { int y=fa[x],z=fa[y],o=ch[y][1]==x; if(!in(y)) ch[z][y==ch[z][1]]=x; fa[x]=z; ch[y][o]=ch[x][!o]; fa[ch[x][!o]]=y; ch[x][!o]=y; fa[y]=x;up(y); } void splay(int x) { int y,z; while(!in(x)) { y=fa[x]; z=fa[y]; if(!in(y)) rotate(((x==ch[y][0])==(y==ch[z][0]))?y:x); rotate(x); } up(x); } void access(int x) { for(int y=0;x;x=fa[y=x]) { splay(x); if(ch[x][1]) { g[x].a+=max(f[ch[x][1]].a,f[ch[x][1]].c); g[x].c+=f[ch[x][1]].a; } if(y) { g[x].a-=max(f[y].a,f[y].c); g[x].c-=f[y].a; } g[x].b=g[x].a; ch[x][1]=y; up(x); } } void update(int x,long long sum) { access(x); splay(x); g[x].c+=sum,up(x); } int main() { ios::sync_with_stdio(false),cin.tie(0),cout.tie(0); int n,m; long long sum=0; string s; cin>>n>>m>>s; for(int i=1;i<=n;i++) { cin>>w[i]; sum+=w[i]; } for(int i=1;i<n;i++) { int a,b; cin>>a>>b; add(a,b); add(b,a); } dfs(1); while(m--) { int a,x,b,y; cin>>a>>x>>b>>y; update(a,x?-INF:INF); update(b,y?-INF:INF); splay(1); long long ans=sum-max(f[1].a,f[1].c)+(2-x-y)*INF; if(ans>INF) cout<<-1<<endl; else cout<<ans<<endl; update(a,x?INF:-INF); update(b,y?INF:-INF); } return 0; }