【點分治】【FFT】2019雅禮集訓 bracket
阿新 • • 發佈:2019-01-12
題目:
分析:
太過套路這裡就簡單說說
顯然,當詢問數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]);
}