题目:
分析:
太过套路这里就简单说说
显然,当询问数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;elseladd=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]);
}