1. 程式人生 > >bzoj 5072 [Lydsy1710月賽]小A的樹——樹形dp

bzoj 5072 [Lydsy1710月賽]小A的樹——樹形dp

大小 color targe using pre namespace put 原來 base

題目:https://www.lydsy.com/JudgeOnline/problem.php?id=5072

發現對於每個子樹,黑點個數確定時,連通塊的大小取值範圍一定是一段區間;所以考慮只最小化最小值、最大化最大值,記 f 和 g 簡單dp即可。

註意可能從當前子樹裏選0個點!此時會用自己更新自己!!所以要先復制一份原來的用來更新!

快速回答詢問,本可以記差分數組,每個子樹算完後給合法部分區間賦值;但空間開不下。

於是絞盡腦汁,終於想出可以開 bool 數組分塊來賦值!!然而WA得不行。

交流後發現那個“取值是一段區間”的性質,在全局也是適用的(很明顯……)!所以只要更新一下合法的最值就行了……

然後對拍半天 bool 分塊,發現因為有 0 的值,所以標號應該是 0~base-1 這樣;而且代碼裏註釋的那個部分是 < 和 >= 而不是 <= 和 >!

然後又因為數據生成出錯而以為自己還是不對而又拍、查了半天;最後分塊的方法雖然慢一點,但也A了。感覺很好!

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int N=5002,M=73;
int T,n,q,base,hd[N],xnt,to[N<<1],nxt[N<<1],siz[N],f[N][N],g[N][N],tf[N],tg[N];
bool b[N],ok[N][N],ok2[M][N];//siz,black int rdn() { int ret=0;bool fx=1;char ch=getchar(); while(ch>9||ch<0){if(ch==-)fx=0;ch=getchar();} while(ch>=0&&ch<=9) ret=(ret<<3)+(ret<<1)+ch-0,ch=getchar(); return fx?ret:-ret; } void add(int x,int y) { to[++xnt]=y;nxt[xnt]=hd[x];hd[x]=xnt; to[
++xnt]=x;nxt[xnt]=hd[y];hd[y]=xnt; } int calc(int x){return x/base+1;}//0~base-1 void dfs(int cr,int fa) { f[cr][b[cr]]=g[cr][b[cr]]=1; siz[cr]=b[cr]; for(int i=hd[cr],v;i;i=nxt[i]) if((v=to[i])!=fa) { dfs(v,cr); memcpy(tf,f[cr],sizeof f[cr]); memcpy(tg,g[cr],sizeof g[cr]); for(int j=siz[cr]+siz[v];j>=b[cr];j--) for(int k=max((int)b[v],j-siz[cr]);k<=siz[v]&&k<=j;k++) { f[cr][j]=min(f[cr][j],tf[j-k]+f[v][k]); g[cr][j]=max(g[cr][j],tg[j-k]+g[v][k]); } siz[cr]+=siz[v]; } /* for(int i=0;i<=siz[cr];i++) f[0][i]=min(f[0][i],f[cr][i]), g[0][i]=max(g[0][i],g[cr][i]); */ for(int i=0;i<=siz[cr];i++) { if(f[cr][i]>g[cr][i])continue; int l=calc(f[cr][i]),r=calc(g[cr][i]); if(r-l<=1) { for(int j=f[cr][i];j<=g[cr][i];j++) ok[j][i]=1; } else { for(int j=l+1;j<r;j++)ok2[j][i]=1; int lm=l*base; for(int j=f[cr][i];j<lm;j++)ok[j][i]=1;//< lm=(r-1)*base; for(int j=g[cr][i];j>=lm;j--)ok[j][i]=1;//>= } } } int main() { T=rdn(); while(T--) { n=rdn(); q=rdn(); base=sqrt(n); memset(hd,0,sizeof hd); xnt=0; memset(ok,0,sizeof ok); memset(ok2,0,sizeof ok2); for(int i=1,u,v;i<n;i++) { u=rdn(); v=rdn(); add(u,v); } for(int i=1;i<=n;i++)b[i]=rdn(); memset(f,0x3f,sizeof f); memset(g,-2,sizeof g); dfs(1,0); for(int i=1,x,y,d;i<=q;i++) { x=rdn(); y=rdn(); d=calc(x); puts((ok[x][y]||ok2[d][y])?"YES":"NO"); //puts(x>=f[0][y]&&x<=g[0][y]?"YES":"NO"); } puts(""); } return 0; }

bzoj 5072 [Lydsy1710月賽]小A的樹——樹形dp