传送门
解析:
真的令人窒息今年这道题。。。
思路:
首先我们要先会O(nm)O(nm)O(nm)的DPDPDP做法。
考虑每个位置DP出选与不选在的最小代价。
显然随手就转移了。
然后限制就是把所有限制不能取的方案的代价设置成INFINFINF,然后就可以DP乱搞了。
然后我们发现每次修改的只有点到rootrootroot的路径上的决策。
于是就可以LCTLCTLCT维护每条链上的决策了,用矩阵进行决策的转移就行了。
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc get_char
#define pc put_char
#define cs const
namespace IO{
cs int Rlen=1<<18|1;
char buf[Rlen],*p1,*p2;
char obuf[Rlen],*p3=obuf,*p4=obuf+Rlen;
inline char get_char(){
return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
}
inline int getint(){
re int num;
re char c;
while(!isdigit(c=gc()));num=c^48;
while(isdigit(c=gc()))num=num*10+(c^48);
return num;
}
inline void put_char(cs char &c){
*p3++=c;
if(p3==p4)fwrite(obuf,1,Rlen,stdout),p3=obuf;
}
inline void outint(ll a){
static char ch[23];
if(a==0)pc('0');
if(a<0)pc('-'),a=-a;
while(a)ch[++ch[0]]=a-a/10*10,a/=10;
while(ch[0])pc(ch[ch[0]--]^48);
}
inline void FLUSH(){
if(p3==obuf)return ;
fwrite(obuf,1,p3-obuf,stdout);
p3=obuf;
}
}
using namespace IO;
cs int N=100005;
cs ll INF=0x3f3f3f3f3f3f3f;
vector<int> edge[N];
inline void addedge(int u,int v){
edge[u].push_back(v);
edge[v].push_back(u);
}
struct matrix{
ll a[2][2];
matrix(ll v=INF){a[1][1]=a[1][0]=a[0][0]=a[0][1]=v;}
friend matrix operator*(cs matrix &A,cs matrix &B){
matrix C;
for(int re i=0;i<=1;++i)
for(int re j=0;j<=1;++j)
for(int re k=0;k<=1;++k)
C.a[i][k]=min(C.a[i][k],A.a[i][j]+B.a[j][k]);
return C;
}
};
typedef struct splay_node *point;
struct splay_node{
point son[2],fa;
matrix a;ll val[2];
#define lc son[0]
#define rc son[1]
inline void pushup(){
a.a[1][0]=a.a[1][1]=val[1];
a.a[0][1]=val[0];
a.a[0][0]=INF;
if(rc)a=a*rc->a;
if(lc)a=lc->a*a;
}
inline void modify(point b,int sign){
ll nothave=min(b->a.a[1][0],b->a.a[1][1]);
ll have=min(nothave,min(b->a.a[0][0],b->a.a[0][1]));
val[0]+=sign*nothave;
val[1]+=sign*have;
}
inline bool isroot()cs{return !fa||(fa->lc!=this&&fa->rc!=this);}
inline bool which()cs{return fa->rc==this;}
};
int val[N];
struct Link_Cut_Tree{
splay_node t[N];
void dfs(int u,int fa){
re point now=&t[u];
now->val[0]=0;
now->val[1]=val[u];
for(int re e=0;e<edge[u].size();++e){
int v=edge[u][e];
if(v==fa)continue;
dfs(v,u);
}
now->pushup();
if(fa){
t[fa].modify(now,1);
now->fa=&t[fa];
}
}
inline void init(){dfs(1,0);}
inline void Rotate(point now){
re point Fa=now->fa,FA=Fa->fa;
re bool pos=now->which();
if(FA&&!Fa->isroot())FA->son[Fa->which()]=now;
Fa->son[pos]=now->son[!pos];
if(Fa->son[pos])Fa->son[pos]->fa=Fa;
now->son[!pos]=Fa;
Fa->fa=now;
now->fa=FA;
Fa->pushup();
now->pushup();
}
inline void Splay(point now){
for(point re Fa=now->fa;!now->isroot();Rotate(now),Fa=now->fa)
if(!Fa->isroot())Rotate(now->which()==Fa->which()?Fa:now);
}
inline void access(point now){
for(point re son=NULL;now;son=now,now=now->fa){
Splay(now);
if(now->rc)now->modify(now->rc,1);
now->rc=son;
if(now->rc)now->modify(now->rc,-1);
now->pushup();
}
}
inline void modify(int pos,bool f,ll add){
point now=&t[pos];
access(now);
Splay(now);
now->val[!f]+=add;
now->pushup();
}
inline ll query(){
re point now=&t[1];
Splay(now);
ll ans=min(min(now->a.a[1][0],now->a.a[1][1]),min(now->a.a[0][0],now->a.a[0][1]));
return ans>=INF?-1:ans;
}
}LCT;
int n,m;
signed main(){
n=getint();
m=getint();
getint();
for(int re i=1;i<=n;++i){
val[i]=getint();
}
for(int re i=1;i<n;++i){
re int u=getint(),v=getint();
addedge(u,v);
}
LCT.init();
while(m--){
re int u=getint(),tu=getint();
re int v=getint(),tv=getint();
LCT.modify(v,tv,INF);
LCT.modify(u,tu,INF);
outint(LCT.query());pc('\n');
LCT.modify(u,tu,-INF);
LCT.modify(v,tv,-INF);
}
FLUSH();
return 0;
}