1. 程式人生 > >【點分治】【FFT】2019雅禮集訓 bracket

【點分治】【FFT】2019雅禮集訓 bracket

題目:

在這裡插入圖片描述


分析:

太過套路這裡就簡單說說
顯然,當詢問數k很小時,就是個裸的點分治題。
現在k變大了。那就FFT算貢獻。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<vector>
#define SF scanf
#define PF printf
#define MAXN 100010
using namespace std;
typedef long long ll;
const double Pi=acos(-1);
vector<
int> a[MAXN]; bool used[MAXN]; int siz[MAXN],siz1[MAXN]; struct cpx{ double r,i; cpx () {} cpx(double r1,double i1):r(r1),i(i1) {} cpx operator +(const cpx &a) const { return cpx(r+a.r,i+a.i); } cpx operator -(const cpx &a) const { return cpx(r-a.r,i-a.i); } cpx operator *(const
cpx &a) const { return cpx(r*a.r-i*a.i,i*a.r+r*a.i); } cpx operator *(double b) const { return cpx(r*b,i*b); } }; void FFT(cpx A[],int N,int flag){ for(int i=1,j=0;i<N;i++){ for(int d=N;j^=d>>=1,~j&d;); if(i<j) swap(A[i],A[j]); } for(int i=1;i<N;i<<=1
){ cpx wn=cpx(cos(Pi/i),sin(Pi/i)); if(flag) wn.i*=-1.0; for(int j=0;j<N;j+=(i<<1)){ cpx w=cpx(1,0); for(int k=0;k<i;k++,w=w*wn){ cpx x=A[j+k],y=w*A[i+j+k]; A[j+k]=x+y; A[i+j+k]=x-y; } } } if(flag) for(int i=0;i<N;i++) A[i].r=A[i].r/double(N); } void mul(int A[],int B[],int N,int M,int res[]){ static cpx A1[MAXN],B1[MAXN]; for(int i=0;i<N;i++) A1[i].r=A[i]; for(int i=0;i<M;i++) B1[i].r=B[i]; int p=1; while(p<=N+M) p<<=1; FFT(A1,p,0); FFT(B1,p,0); for(int i=0;i<p;i++) A1[i]=A1[i]*B1[i]; FFT(A1,p,1); for(int i=0;i<N+M;i++) res[i]=int(A1[i].r+0.5); for(int i=0;i<p;i++) A1[i].r=A1[i].i=B1[i].r=B1[i].i=0; } void get_sz(int x,int fa=0){ siz[x]=1; for(int i=0;i<int(a[x].size());i++){ int u=a[x][i]; if(u==fa||used[u]) continue; get_sz(u,x); siz[x]+=siz[u]; } } int get_maxs(int x,int sizall,int fa=0){ int res=0; siz1[x]=sizall-siz[x]; for(int i=0;i<int(a[x].size());i++){ int u=a[x][i]; if(u==fa||used[u]) continue; int res1=get_maxs(u,sizall,x); if(res==0||siz1[res1]<siz1[res]) res=res1; siz1[x]=max(siz1[x],siz[u]); } if(res==0||siz1[x]<siz1[res]) res=x; return res; } int find_g(int x){ get_sz(x); return get_maxs(x,siz[x]); } vector<int> f1[MAXN],f2[MAXN]; ll ans[MAXN]; int val[MAXN],f[MAXN],g[MAXN]; int dfs(int x,int fa,int maxd,int mind,int s1,int s2,int pre=0){ pre+=val[x]; int res=1; if(maxd<pre){ maxd=pre; f1[pre].push_back(0); s1=1; } else if(maxd==pre){ f1[pre].push_back(s1); s1++; } if(mind>pre){ mind=pre; f2[-pre].push_back(0); s2=1; } else if(mind==pre){ f2[-pre].push_back(s2); s2++; } for(int i=0;i<int(a[x].size());i++){ int u=a[x][i]; if(used[u]||u==fa) continue; res=max(res,dfs(u,x,maxd,mind,s1,s2,pre)+1); } return res; } void calc(int md,int flag,int Gval){ int maxt=0,radd=0,ladd=0; if(flag==1){ f1[0].push_back(0); f2[0].push_back(0); } if(Gval==1) radd=1; else ladd=1; for(int i=0;i<=md;i++){ if(f1[i+ladd].size()&&f2[i+radd].size()){ maxt=0; for(int j=0;j<int(f1[i+ladd].size());j++){ f[f1[i+ladd][j]]++; maxt=max(maxt,f1[i+ladd][j]+1); } for(int j=0;j<int(f2[i+radd].size());j++){ g[f2[i+radd][j]+1]++; maxt=max(maxt,f2[i+radd][j]+1+1); } // for(int i=0;i<maxt;i++) // PF("[%d %d]\n",f[i],g[i]); // PF("~~~~~~~~~~~~~~~~~~~\n"); mul(f,g,maxt,maxt,f); for(int j=0;j<2*maxt;j++){ ans[j]+=(f[j]*flag); f[j]=g[j]=0; } } f1[i].clear(); f2[i].clear(); } } void solve(int x){ int G=find_g(x); used[G]=1; int maxd=0; // PF("[%d]\n",G); for(int i=0;i<int(a[G].size());i++){ int u=a[G][i]; if(used[u]) continue; maxd=max(maxd,dfs(u,G,0,0,1,1)); } // for(int i=0;i<=maxd;i++) // PF("[%d %d]\n",f1[i].size(),f2[i].size()); // PF("======================\n"); calc(maxd,1,val[G]); // for(int i=1;i<7;i++) // PF("[%lld]",ans[i]); // PF("\n"); for(int i=0;i<int(a[G].size());i++){ int u=a[G][i]; if(used[u]) continue; int maxd1=dfs(u,G,0,0,1,1); calc(maxd1,-1,val[G]); // PF("{%d -> %d}\n",G,u); // for(int i=0;i<7;i++) // PF("[%lld]",ans[i]); // PF("\n"); } for(int i=0;i<int(a[G].size());i++){ int u=a[G][i]; if(used[u]) continue; solve(u); } } int n,m,u,v; char s[20]; int main(){ SF("%d",&n); for(int i=1;i<n;i++){ SF("%d%d",&u,&v); a[u].push_back(v); a[v].push_back(u); } for(int i=1;i<=n;i++){ SF("%s",s); if(s[0]=='(') val[i]=1; else val[i]=-1; } solve(1); SF("%d",&m); for(int i=1;i<=m;i++){ SF("%d",&u); PF("%lld\n",ans[u]); } // for(int i=1;i<=n;i++) // PF("%lld\n",ans[i]); }