[DP](計蒜之道2016程式設計大賽初賽第六場)微軟的員工福利 題解.md
阿新 • • 發佈:2018-12-11
[DP] (計蒜之道2016初賽第六場) 微軟的員工福利 題解
題目大意
給出一個個節點的有根樹,每個點可以賦予給定的兩個值其中之一,這棵樹的權值就是所有節點的值,但是對於每個非葉節點節點而言,如果在它和它所有兒子節點中最大值與最小值的差大小為,那麼需要在樹的權值中扣除,求這棵樹的最大權值。
解題分析
這道題非A即B,所以典型的2-SAT
什麼是two pointers
示例程式碼
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long LL;
const int maxn=100005,maxm=200005;
int n,now, v[maxn][2],tot,son[maxm],nxt[maxm],lnk[maxn],ha[maxm];
LL f[maxn][2];
struct data{
int x,y;
data (int x=0,int y=0):x(x),y(y){}
bool operator < (const data b)const{return x<b.x;}
}w[maxm];
inline void readi(int &x){
x=0; char ch=getchar();
while ('0'>ch||ch>'9') ch=getchar();
while ( '0'<=ch&&ch<='9') {x=x*10+ch-'0'; ch=getchar();}
}
void _add(int x,int y){son[++tot]=y; nxt[tot]=lnk[x]; lnk[x]=tot;}
void _init(){
freopen("B.in","r",stdin);
freopen("B.out","w",stdout);
readi(n); tot=0;
for (int i=1;i<=n;i++) {readi(v[i][0]); readi(v[i][1]); if(v[i][0]>v[i][1]) swap(v[i][0],v[i][1]);}
for (int i=1,x,y;i<n;i++){
readi(x); readi(y); _add(x,y); _add(y,x);
}
}
int gei(int L,int R,int x){
int A=(L<=v[x][0]&&v[x][0]<=R),B=(L<=v[x][1]&&v[x][1]<=R); return B*2+A;
}
void _dfs(int x,int fa){
for (int j=lnk[x];j;j=nxt[j])
if (son[j]!=fa) _dfs(son[j],x);
now=0;
for (int j=lnk[x];j;j=nxt[j])
if (son[j]!=fa) {w[++now]=data(v[son[j]][0],son[j]); w[++now]=data(v[son[j]][1],son[j]);}
if (!now) {f[x][0]=v[x][0]; f[x][1]=v[x][1]; return;}
w[++now]=data(v[x][0],x); w[++now]=data(v[x][1],x);
sort(w+1,w+now+1); LL mx[2]; mx[0]=mx[1]=((LL)1<<60)*(-1);
for (int D=0;D<=w[now].x-w[1].x+1000;D+=1000){ //列舉極差
int k=0; LL sum=-(LL)D/1000*666*x;
for (int i=1;i<=now;i++) ha[w[i].y]=0;
for (int i=1,j=1,t,L,R;i<=now;i=t){
if (v[x][1]<w[i].x) break;
L=w[i].x; R=L+D;
for (;j<=now&&w[j].x<=R;ha[w[j++].y]++)
if (ha[w[j].y]) sum+=max(f[w[j].y][0],f[w[j].y][1])-f[w[j].y][0];
//如果兩個都可以選上,貪心選較大的
else {sum+=f[w[j].y][gei(L,R,w[j].y)==2]; k++;}
//如果只有一個,優先考慮小的
if (k==(now>>1)){
int te=gei(L,R,x);
if (te&1) mx[0]=max(mx[0],sum+v[x][0]);
if (te>1) mx[1]=max(mx[1],sum+v[x][1]);
} //更新答案
for (t=i;w[i].x==w[t].x&&t<=now;ha[w[t++].y]--){
if (ha[w[t].y]==1) {sum-=f[w[t].y][gei(L,R,w[t].y)==2]; k--;}
else sum-=max(f[w[t].y][0],f[w[t].y][1])-f[w[t].y][1];
}//區間右移,去除前面的
}
}
f[x][0]=mx[0]; f[x][1]=mx[1];
}
void _solve(){
_dfs(1,0); printf("%lld",max(f[1][0],f[1][1]));
}
int main()
{
_init();
_solve();
return 0;
}