もちろん、それはないネストDDP、もちろん裸DP問題の最適化を検討しているこの質問を書きますが、それは非常に面倒な質問です、そして、それは黒の問題となります。
まず第一に、これはグラフの最大の独立したセットを求める権利で、パーティモデルのボスではありません。
王が制約を考慮していない、ある
\ [DP [x]は[0 ] + = DP [Y] [1] \\ DP [X] [1] + =分(DP [Y] [1]、DP [Y ] [0])\]
今の制限を考慮して、各時間の制約はDP、リーチの複雑行う場合には、\(O(N ^ 2)\) 、余裕がありません。
明らかに、これらの制限のために、すべての変更は、他のほとんどの州には影響しません。
制約のために、私たちは別に、最初の唯一の都市の限界まで場合を考えると考えます。
軍隊は必要としない場合、それはあったであろう、この時点では木がすべてのサブ最適なソリューションであるため、その後、市は軍事的プレゼンスを必要とするなら、それは我々が最良の場合には軍隊を必要とする場合、それは効果がありませんされているだろう、それが唯一のだろうそれは衝撃のルートパスに最適な解決策です。
市は、上記の場合に非常に類似した駐留ない求められた場合、それはニーズを駐留されているならば、それはルートノードへのパスに影響します。
要約すると、我々はそれを修正するには、rootの間にいくつかの状態のパスに、制約のそれぞれについて、2点のみを考慮することができますか?答えはイエスです。
ノードは変更されているものとする(X \)\。まず、加えてこの時間\(SIMルート\ X \)表される経路上の状態ノードは、他の条件が最適です。このパスに更新し、このパスは、実際のDPを行って、そして力のために\(Xの\)選択された又はそれによって転写を制限する、選択されていません。
明らかにこれは可能ですが、複雑さはまだある\(O(N ^ 2)\) 、我々は、最適化のいくつかの手段を必要としています。
私たちの更新は、私たちが自然に各ポイントの転送を処理するために(彼らは木のチェーンを維持している)、乗算またはツリーセクションを使用するのではと思いますが、チェーン用のチェーンを簡単に見つけることができます。
例えば、乗算するには。
裸DP、1つのジャンプずつ、息子からの各転送の最初のステップを考えてみましょう。その後、我々は、段落によってその中に既存の情報から、各転送を段落をジャンプすることができますか?もちろん。
まず一点のみの場合を考えます。
私たちがしたい場合は(X \)\上限を、我々は、全体マップのような便利な分析になるかもしれません
緑色の部分がある場合は、\(X \)最適解サブツリー。
もちろん私たちは一点を修正した後、最適解への影響は一定で、生産の新しい最適なソリューションは、私たちは事前にアウトすることができますいくつかの手段によって意味し、特定のです。
この中で(オプションを選択しないようになる、選択されていない選択となる)最適が変動する各点を乗算することによって前処理を考える(Xルートの\ \シム)\、鎖中に生成された新たな最適解をすなわち、ジャンプの後の一定時間セグメントDP最適解を修正するための前処理。
その後から、\(X \)木の乗数ジャンプ\(ルート\) 、新しい最適なソリューションを合わせ、答えは条件の下で制限されました。
裸のDPが行わ上で実際には、私たちの前乗算をベースにしています。原点を乗算すると、DOのDP、各状態に対する最適解を示し、その後制約を追加すると言い換えると、情報が使用されます。
画像を言えば、この事前乗算がDP DP設定されています。
そして、この乗算器はどのようにそれを行うには?
大きいサブ問題にいくつかのより小さなサブ問題の合併、これらのより小さなサブ問題が交差することができない場合、それ以外の場合は、バイナリに基づいて分割することができない、明らかに、状態を描写考える大きいサブ問題に合流。さらに、サブの質問は全体の状態空間をカバーしなければなりません。状態の定義は、我々が漏れないようにしたい場合には、あります。
我々は唯一のはいけない乗じたレコードと考えるのは難しいことではないような場合であること、最初のポイント、\(X \)跳ね上がった状態(0/1)だけでなく、それを記録するために\(^ K \ 2)状態の段階の祖先を。
第二の点の範囲は含ま状態を思い付くことは困難ではありません。
セット\は(F [0/1] [0/1 ] [K] [X] \) を表し\(X \)ノードになり、0が使用できない場合、オプション、アップ\(2 ^ k個の\)ステップ祖先\(Y \)は、オプション0,1、オプションではありません、\ (Y \)が除去される\(X \)と\(X \)元の最適解サブツリーの新しい最適他のすべてのサブツリーソリューション。
以下、これをノード3と仮定されている\(X \)\(2 ^ k個の\)祖先状態が赤色部分であります
3 \(2 ^ K \)祖先は(されているものとルート\)は(\青色部分の状態により表されます)。
これが答えた後、良いマージ状態、統計的なプロセスになることが、私たちはただ列挙\(X \)乗算する状態とジャンプを。
ノードのための\(Y \)、親に\(X \)がある
\ [[1] [0 F Y [1] -dp] [0] [Y] = DP [0] [X] ] \\ [0] [1 F DP(DP [1] [Y] [0] [Y]はfは= [1] [1] [0] [Y] = DP [1] [X] -min [0] [Y])\ ]
得られた転送(のCaO)
\ [F [0] [0] [J] [Y] =分(F [0] [0] [J-1] [Y] + F [0] [0] [J-1 ] [FA]、F [0 ] [1]〜[J-1] [Y] + F [1] [0] [J-1] [FA])\\ F [0] [1]〜[J] [ Yが(分= F [0 ] [0] [J-1] [Y] + F [0] [1]〜[J-1] [FA]、F [0] [1]〜[J-1] [ Y] + F [1] [ 1]〜[J-1] [FA])\\ F [1] [0] [J] [Y] =分(F [1] [0] [J-1] [ Y] + F [0] [ 0] [J-1] [FA]、F [1] [1]〜[J-1] [Y] + F [1] [0] [J-1] [FA] )\\ F [1] [1 ] [J] [Y] =分([1] [0] [J-1] [y]のF + F [0] [1]〜[J-1] [FA] 、F [1] [1]〜
[J-1] [Y] + F [1] [1]〜[J-1] [FA])\] 次に、答えはもちろん、統計的な答えを倍増して、カウントすることです。
ルートノードまで、最適解を倍加の新しい点を組み込むように修正される2つの異なる状態から始まります。
二つの点を変更するための\(X、Y \) 、我々は同じLCAを求めるような状況、最初の統計\(X- \ SIM LCA(X、Y)、SIM LCA(X、Y)\ Y- \) 、次いで統計\(LCA(x、y)は SIMルート\ \)があってもよいです。
細部へのこだわり、\(X、Yの\) 2つのジャンプ\(LCAの\)私たちは彼らの元の2つの最適解を引く必要があり、同時に息子、その後、さらに上のジャンプします。
複雑さを軽減するために\(O(nlogn)\) 。
ツリー断面はまた、理由、前処理の変更後に最適なソリューションです。
参照コード
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<string>
#include<cstdlib>
#include<queue>
#include<vector>
#define INF 0x3f3f3f3f
#define PI acos(-1.0)
#define N 100010
#define MOD 2520
#define E 1e-12
#define ll long long
using namespace std;
inline ll read()
{
ll f=1,x=0;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
return x*f;
}
struct rec{
int next,ver;
}g[N<<1];
int head[N],tot,n,m;
ll dp[2][N],f[2][2][21][N],gi[21][N],t,dep[N],w[N];
inline void add(int x,int y)
{
g[++tot].ver=y;
g[tot].next=head[x],head[x]=tot;
}
inline void dfs(int x,int fa)
{
dp[1][x]=w[x];dep[x]=dep[fa]+1;
f[0][0][0][x]=INF,gi[0][x]=fa;
for(int j=1;j<t;++j) gi[j][x]=gi[j-1][gi[j-1][x]];
for(int i=head[x];i;i=g[i].next){
int y=g[i].ver;
if(y==fa) continue;
dfs(y,x);
dp[0][x]+=dp[1][y];
dp[1][x]+=min(dp[1][y],dp[0][y]);
}
}
inline void init()
{
queue<ll> q;
q.push(1);
f[1][0][0][1]=dp[0][0]-dp[1][1];
f[0][1][0][1]=f[1][1][0][1]=dp[1][0]-min(dp[1][1],dp[0][1]);
while(q.size()){
ll x=q.front();q.pop();
for(int i=head[x];i;i=g[i].next){
int y=g[i].ver;
if(y==gi[0][x]) continue;
f[1][0][0][y]=dp[0][x]-dp[1][y];
f[0][1][0][y]=f[1][1][0][y]=dp[1][x]-min(dp[1][y],dp[0][y]);
for(int j=1;j<t;++j){
int fa=gi[j-1][y];
f[0][0][j][y]=min(f[0][0][j-1][y]+f[0][0][j-1][fa],f[0][1][j-1][y]+f[1][0][j-1][fa]);
f[0][1][j][y]=min(f[0][0][j-1][y]+f[0][1][j-1][fa],f[0][1][j-1][y]+f[1][1][j-1][fa]);
f[1][0][j][y]=min(f[1][0][j-1][y]+f[0][0][j-1][fa],f[1][1][j-1][y]+f[1][0][j-1][fa]);
f[1][1][j][y]=min(f[1][0][j-1][y]+f[0][1][j-1][fa],f[1][1][j-1][y]+f[1][1][j-1][fa]);
}
q.push(y);
}
}
}
inline ll get(ll x,int a,ll y,int b)
{
ll ans=0,lca;
if(dep[x]<dep[y]) swap(x,y),swap(a,b);
ll x0=INF,x1=INF,y0=INF,y1=INF,l0=INF,l1=INF;
a?x1=dp[1][x]:x0=dp[0][x],b?y1=dp[1][y]:y0=dp[0][y];
for(int j=t;j>=0;--j){
ll t0=x0,t1=x1;
if(dep[gi[j][x]]>=dep[y]){
x0=min(t0+f[0][0][j][x],t1+f[1][0][j][x]);
x1=min(t0+f[0][1][j][x],t1+f[1][1][j][x]);
x=gi[j][x];
}
}
if(x==y) lca=x,b?l1=x1:l0=x0;
else {
for(int j=t;j>=0;--j){
if(gi[j][x]!=gi[j][y]){
ll t0=x0,t1=x1,p0=y0,p1=y1;
x0=min(t0+f[0][0][j][x],t1+f[1][0][j][x]);
x1=min(t0+f[0][1][j][x],t1+f[1][1][j][x]);
y0=min(p0+f[0][0][j][y],p1+f[1][0][j][y]);
y1=min(p0+f[0][1][j][y],p1+f[1][1][j][y]);
x=gi[j][x],y=gi[j][y];
}
}
lca=gi[0][x];
l0=dp[0][lca]-dp[1][x]-dp[1][y]+x1+y1;
l1=dp[1][lca]-min(dp[0][x],dp[1][x])-min(dp[0][y],dp[1][y])+min(x1,x0)+min(y1,y0);
}
if(lca==1) ans=min(l0,l1);
else{
for(int j=t;j>=0;--j){
if(dep[gi[j][lca]]>1){
ll t0=l0,t1=l1;
l0=min(t0+f[0][0][j][lca],t1+f[1][0][j][lca]);
l1=min(t0+f[0][1][j][lca],t1+f[1][1][j][lca]);
lca=gi[j][lca];
}
}
ans=min(dp[0][1]-dp[1][lca]+l1,dp[1][1]-min(dp[0][lca],dp[1][lca])+min(l1,l0));
}
return ans<INF?ans:-1;
}
int main()
{
n=read(),m=read();
char op[5];
cin>>op;
t=log2(n)+1;
for(int i=1;i<=n;++i) w[i]=read();
for(int i=1;i<n;++i){
ll u=read(),v=read();
add(u,v),add(v,u);
}
dfs(1,0);
init();
while(m--){
ll x=read(),a=read(),y=read(),b=read();
if(a==0&&b==0&&(gi[0][x]==y||gi[0][y]==x)){
puts("-1");continue;
}
printf("%lld\n",get(x,a,y,b));
}
return 0;
}