3.27 模拟赛

T1 

题目大意:

一棵树有正边权,$Q$次询问,询问$x$与编号在$[l,r]$之间的点的最小距离

思路:

建立点分树,由于在每个分治重心内任意两个点的lca可以看做重心

我们可以预处理出一个点到他点分树上所有的祖先的距离,每个点最多处理$log$个距离

对每个重心维护动态开点线段树,把每个点暴力加入到它点分树上祖先的线段树

查询的时候暴力查询所有祖先的线段树即可

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cstdlib>
 5 #include<cmath>
 6 #include<algorithm>
 7 #include<queue>
 8 #include<vector>
 9 #include<map>
10 #include<set>
11 #define ll long long
12 #define db double
13 #define inf 21390621430000000LL
14 #define MAXN 100100
15 #define rep(i,s,t) for(register int i=(s),i##__end=(t);i<=i##__end;++i)
16 #define dwn(i,s,t) for(register int i=(s),i##__end=(t);i>=i##__end;--i)
17 #define ren for(register int i=fst[x];i;i=nxt[i])
18 #define pb(i,x) vec[i].push_back(x)
19 #define pls(a,b) (a+b)%MOD
20 #define mns(a,b) (a-b+MOD)%MOD
21 #define mul(a,b) (1LL*(a)*(b))%MOD
22 using namespace std;
23 inline int read()
24 {
25     int x=0,f=1;char ch=getchar();
26     while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
27     while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
28     return x*f;
29 }
30 int n,nxt[MAXN<<1],fst[MAXN],to[MAXN<<1],cnt,val[MAXN<<1];
31 int sz[MAXN],mx[MAXN],Mx,Sum,Rt,vis[MAXN],dep[MAXN],fa[MAXN];
32 ll dis[MAXN][20];
33 void add(int u,int v,int w) {nxt[++cnt]=fst[u],fst[u]=cnt,to[cnt]=v,val[cnt]=w;}
34 void getrt(int x,int pa)
35 {
36     sz[x]=1,mx[x]=0;ren if(to[i]^pa&&!vis[to[i]])
37         {getrt(to[i],x);sz[x]+=sz[to[i]];mx[x]=max(mx[x],sz[to[i]]);}
38     mx[x]=max(mx[x],Sum-sz[x]);if(mx[x]<Mx) Mx=mx[x],Rt=x;
39 }
40 void Get(int x,int pa,int d){ren if(!vis[to[i]]&&to[i]^pa) dis[to[i]][d]=dis[x][d]+val[i],Get(to[i],x,d);}
41 void div(int x)
42 {
43     vis[x]=1;dis[x][dep[x]]=0;Get(x,0,dep[x]);
44     ren if(!vis[to[i]]) 
45         {Sum=sz[to[i]],Mx=n+2;getrt(to[i],0);dep[Rt]=dep[x]+1,fa[Rt]=x;div(Rt);}
46 }
47 ll mn[MAXN<<7];int ls[MAXN<<7],rs[MAXN<<7],rt[MAXN],tot;
48 void mdf(int &k,int l,int r,int x,ll w)
49 {
50     if(!k) k=++tot,mn[k]=inf;mn[k]=min(mn[k],w);if(l==r) return ;int mid=l+r>>1;
51     if(x<=mid) mdf(ls[k],l,mid,x,w);else mdf(rs[k],mid+1,r,x,w);
52 }
53 ll query(int k,int l,int r,int a,int b)
54 {
55     if(!k) return inf;if(l==a&&r==b) return mn[k];int mid=l+r>>1;
56     if(b<=mid) return query(ls[k],l,mid,a,b);
57     else if(a>mid) return query(rs[k],mid+1,r,a,b);
58     else return min(query(ls[k],l,mid,a,mid),query(rs[k],mid+1,r,mid+1,b));
59 }
60 void Mdf(int x){for(int anc=x;dep[anc];anc=fa[anc]) mdf(rt[anc],1,n,x,dis[x][dep[anc]]);}
61 ll Query(int x,int l,int r,ll res=inf)
62 {
63     for(int anc=x;dep[anc];anc=fa[anc]){res=min(res,dis[x][dep[anc]]+query(rt[anc],1,n,l,r));}
64     return res;
65 }
66 int main()
67 {
68     n=read();int a,b,c;rep(i,2,n) a=read(),b=read(),c=read(),add(a,b,c),add(b,a,c);
69     Mx=n+2,Sum=n;getrt(1,0);dep[Rt]=1;div(Rt);rep(i,1,n) Mdf(i);
70     int T=read();while(T--) {a=read(),b=read(),c=read();printf("%lld\n",Query(c,a,b));}
71 }
View Code

 

T2 

题目大意:

把$n$个本质不同的东西分给$m$个本质相同的人,定义每种方案的权值为所有人拿到东西的数目成绩

求所有方案的权值和

思路:

对于每个方案的权值,可以看做给方案中对每个人都选一朵花的方案数

则我们可以先枚举出选出的这$m$朵花,即$C_n^m$ 剩下的花随便放即$m^{n-m}$,总方案数为贡献

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cstdlib>
 5 #include<cmath>
 6 #include<algorithm>
 7 #include<queue>
 8 #include<vector>
 9 #include<map>
10 #include<set>
11 #define ll long long
12 #define db double
13 #define inf 2139062143
14 #define MAXN 100100
15 #define MOD 998244353
16 #define rep(i,s,t) for(register int i=(s),i##__end=(t);i<=i##__end;++i)
17 #define dwn(i,s,t) for(register int i=(s),i##__end=(t);i>=i##__end;--i)
18 #define ren for(register int i=fst[x];i;i=nxt[i])
19 #define pb(i,x) vec[i].push_back(x)
20 #define pls(a,b) (a+b)%MOD
21 #define mns(a,b) (a-b+MOD)%MOD
22 #define mul(a,b) (1LL*(a)*(b))%MOD
23 using namespace std;
24 inline int read()
25 {
26     int x=0,f=1;char ch=getchar();
27     while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
28     while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
29     return x*f;
30 }
31 int n,m,pw[MAXN],ipw[MAXN];
32 int q_pow(int bas,int t,int res=1)
33 {
34     for(;t;t>>=1,bas=mul(bas,bas))
35         if(t&1) res=mul(res,bas);return res;
36 }
37 int C(int n,int m) {return mul(pw[n],mul(ipw[m],ipw[n-m]));}
38 int main()
39 {
40     n=read(),m=read();pw[0]=1;rep(i,1,n) pw[i]=mul(pw[i-1],i),ipw[i]=q_pow(pw[i],MOD-2);
41     printf("%d\n",mul(C(n,m),q_pow(m,n-m)));
42 }
View Code

 

T3

题目大意:

求树上选出$m$个点的点独立集的所有方案的权值和,一个方案的权值定义为选出的点的权值的乘积

思路:

设$f_{x,0/1}$表示选不选$x$这个点的答案

考虑合并一个新的子树进来合并,$f_{i+j,0}=t_{i,0}*f{j,0}$ 是一个卷积的形式

则我们可以用$ntt$来合并,但显然复杂度是不满足的

考虑重链剖分,先把重链上每个点的其他儿子的贡献算出来,得到一个$g_{x,0/1}$数组

为了快速合并重链上的信息,我们还需要记录选头不选尾,选尾不选头的情况。这样就可以用分治来优化了

这样一路合并上去就可以得到答案了

(指针可真是个弟弟,谜之分配内存

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<cstdlib>
  5 #include<cmath>
  6 #include<algorithm>
  7 #include<queue>
  8 #include<vector>
  9 #include<map>
 10 #define ll long long
 11 #define db double
 12 #define inf 2139092143
 13 #define MAXN 160100
 14 #define MOD 998244353
 15 #define rep(i,s,t) for(register int i=(s),i##end=(t);i<=i##end;++i)
 16 #define dwn(i,s,t) for(register int i=(s),i##end=(t);i>=i##end;--i)
 17 #define ren(x) for(int i=fst[x];i;i=nxt[i])
 18 #define pls(a,b) (a%MOD+b%MOD)%MOD
 19 #define mns(a,b) ((a%MOD-b%MOD)%MOD+MOD)%MOD
 20 #define mul(a,b) (1LL*(a%MOD)*(b%MOD))%MOD
 21 #define inv(x) q_pow(x,MOD-2)
 22 using namespace std;
 23 inline int read()
 24 {
 25     int x=0,f=1;char ch=getchar();
 26     while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
 27     while(isdigit(ch)) {x=x*10+ch-'0',ch=getchar();}
 28     return x*f;
 29 }
 30 int w[MAXN],n,m,nxt[MAXN<<1],fst[MAXN],to[MAXN<<1],cnt;
 31 int sz[MAXN],hsh[MAXN],hvs[MAXN],fa[MAXN],tot,t[MAXN],tt[MAXN];
 32 void add(int u,int v) {nxt[++cnt]=fst[u],fst[u]=cnt,to[cnt]=v;}
 33 int A[MAXN<<2],B[MAXN<<2],pw[30],ipw[30],rev[MAXN<<2],l2[MAXN<<2],tmp[MAXN<<8],*id=tmp;
 34 int q_pow(int bas,int t,int res=1)
 35 {
 36     for(;t;t>>=1,bas=mul(bas,bas))
 37         if(t&1) res=mul(res,bas);return res;
 38 }
 39 void ntt(int *a,int n,int f)
 40 {
 41     rep(i,0,n-1) if(i<rev[i]) swap(a[i],a[rev[i]]);
 42     for(int i=1;i<n;i<<=1)
 43     {
 44         int wn=f>0?pw[l2[i]+1]:ipw[l2[i]+1];
 45         for(int j=0;j<n;j+=i<<1)
 46         {
 47             int w=1,x,y;
 48             for(int k=0;k<i;++k,w=mul(w,wn))
 49                 x=a[j+k],y=mul(a[j+k+i],w),a[j+k]=pls(x,y),a[j+k+i]=mns(x,y);
 50         }
 51     }
 52     if(f>0) return ;int nv=inv(n);rep(i,0,n-1) a[i]=mul(a[i],nv);
 53 }
 54 struct poly
 55 {
 56     int *a,len;void mem(int x) {len=x,a=id,id+=len;}
 57     poly operator * (const poly &b) const
 58     {
 59         poly res;res.mem(len+b.len-1);int t=l2[res.len]+1,lmt=1<<t;
 60         if(res.len<=100)
 61         {
 62             rep(i,0,len-1) rep(j,0,b.len-1) if(i+j<res.len)
 63                 res.a[i+j]=pls(mul(a[i],b.a[j]),res.a[i+j]);return res;
 64         }
 65         rep(i,0,lmt-1) rev[i]=(rev[i>>1]>>1)|((i&1)<<t-1),A[i]=B[i]=0;
 66         rep(i,0,len-1) A[i]=a[i];rep(i,0,b.len-1) B[i]=b.a[i];
 67         ntt(A,lmt,1);ntt(B,lmt,1);
 68         rep(i,0,lmt-1) A[i]=mul(A[i],B[i]);ntt(A,lmt,-1);
 69         rep(i,0,res.len-1) res.a[i]=A[i];return res;
 70     }
 71     poly operator + (const poly &b) const
 72     {
 73         poly res;res.mem(max(len,b.len));
 74         rep(i,0,res.len-1) res.a[i]=pls((i<len?a[i]:0),(i<b.len?b.a[i]:0));return res;
 75     }
 76 }f[MAXN][2],g[MAXN][2],One,Zero;
 77 poly solve(int l,int r,int D)
 78 {
 79     if(l==r) return f[t[l]][D];int mid=l+r>>1;
 80     return solve(l,mid,D)*solve(mid+1,r,D);
 81 }
 82 struct mat{poly a[2][2];void mem() {a[0][0]=a[0][1]=a[1][1]=a[1][0]=Zero;}};
 83 mat merge(const mat &x,const mat &y)
 84 {
 85     mat res;res.a[1][1]=x.a[1][0]*(y.a[0][1]+y.a[1][1])+x.a[1][1]*y.a[0][1];
 86     res.a[1][0]=x.a[1][0]*(y.a[0][0]+y.a[1][0])+x.a[1][1]*y.a[0][0];
 87     res.a[0][1]=x.a[0][0]*(y.a[0][1]+y.a[1][1])+x.a[0][1]*y.a[0][1];
 88     res.a[0][0]=x.a[0][0]*(y.a[0][0]+y.a[1][0])+x.a[0][1]*y.a[0][0];return res;
 89 }
 90 mat solve(int l,int r)
 91 {
 92     if(l==r) {mat res;res.mem();res.a[0][0]=g[tt[l]][0],res.a[1][1]=g[tt[l]][1];return res;}
 93     int mid=l+r>>1;return merge(solve(l,mid),solve(mid+1,r));
 94 }
 95 void dfs(int x,int pa)
 96 {
 97     fa[x]=pa,hsh[++tot]=x,sz[x]=1;
 98     ren(x) if(to[i]^pa) dfs(to[i],x),sz[x]+=sz[to[i]],hvs[x]=sz[to[i]]>sz[hvs[x]]?to[i]:hvs[x];
 99 }
100 void work(int x)
101 {
102     int l1=0,l2;poly it;mat res;
103     for(int y=x;y;y=hvs[y])
104     {
105         tt[++l1]=y,l2=0;ren(y) if(to[i]^fa[y]&&to[i]^hvs[y]) t[++l2]=to[i];
106         it.mem(2);it.a[0]=0;it.a[1]=w[y];if(!l2) g[y][0]=One,g[y][1]=it;
107         else g[y][0]=solve(1,l2,1),g[y][1]=solve(1,l2,0)*it;
108     }
109     res=solve(1,l1);f[x][0]=res.a[0][0]+res.a[0][1];
110     f[x][1]=f[x][0]+res.a[1][0]+res.a[1][1];
111 }
112 int main()
113 {
114     n=read(),m=read();int a,b;rep(i,1,n) w[i]=read();One.mem(1);One.a[0]=1;
115     rep(i,2,n) a=read(),b=read(),add(a,b),add(b,a);Zero.mem(1);
116     rep(i,2,n<<2) 
117     {
118         l2[i]=l2[i>>1]+1;
119         if(!pw[l2[i]]) pw[l2[i]]=q_pow(3,(MOD-1)/i),ipw[l2[i]]=inv(pw[l2[i]]);
120     }
121     dfs(1,0);dwn(i,n,1) {a=hsh[i];if(hvs[fa[a]]^a) work(a);}
122     printf("%d\n",f[1][1].len>=m+1?f[1][1].a[m]:0);
123 }
View Code

 

posted @ 2019-03-27 18:56  jack_yyc  阅读(166)  评论(0编辑  收藏  举报