求所有可能联通块的第k大值的和,考虑枚举这个值:

$ans=\sum\limits_{i=1}^{W}{i\sum\limits_{S}{[i是第K大]}}$

设cnt[i]为连通块中值>=i的个数

$ans=\sum\limits_{i=1}^{W}{i\sum\limits_{S}{[cnt[i]>=K]-[cnt[i+1]>=K]}}$

$ans=\sum\limits_{i=1}^{W}{\sum\limits_{S}{[cnt[i]>=K]}}$

于是先考虑树上dp,设f[i][j][k]表示以i为根的连通块中,值>=j的数量为k的情况数

然后$ans=\sum\limits_{i=1}^{N}{\sum\limits_{j=1}^{W}{\sum\limits_{k=K}^{N}{f[i][j][k]}}}$

转移和背包类似,所以这样做是$O(N^2W)$的

考虑使用生成函数优化,设$F[i][j]=\sum{f[i][j][k]x^k}$,再设$G[i][j]=\sum{F[s][j]},i是s的祖先$

于是转移就变成了$F[i][j]*=(F[s][j]+1),G[i][j]+=G[s][j],G[i][j]+=F[i][j]$,其中s是i的孩子

同时有初值$F[i][j]=(d[i]>=j?x:1)$,答案就是G[1][*]的K~N项系数的和

然后当然不能真的去乘了..

考虑先将F和G用点值表达,最后再插回来

首先枚举x=1..N+1,然后给每个点i开动态开点的线段树维护F[i][j]和G[i][j]的值

然后用线段树合并来做对应位置的相乘和相加

具体来说,我们让线段树上的结点维护一个作用在$(f,g)$上的变换$(a,b,c,d)$,使得最终得到$(af+b,cf+d+g)$

然后也不难得到变换的乘法(有结合律但没有交换律)

然后就可以做了 复杂度我也不会分析 反正有可能跑的比暴力还慢

别忘了回收掉不用的点

  1 #include<bits/stdc++.h>
  2 #define pa pair<int,int>
  3 #define CLR(a,x) memset(a,x,sizeof(a))
  4 #define MP make_pair
  5 #define fi first
  6 #define se second
  7 using namespace std;
  8 typedef long long ll;
  9 typedef unsigned long long ull;
 10 typedef unsigned int ui;
 11 typedef long double ld;
 12 const int maxn=1700,maxp=3e6;
 13 const int P=64123;
 14
 15 inline char gc(){
 16     return getchar();
 17     static const int maxs=1<<16;static char buf[maxs],*p1=buf,*p2=buf;
 18     return p1==p2&&(p2=(p1=buf)+fread(buf,1,maxs,stdin),p1==p2)?EOF:*p1++;
 19 }
 20 inline ll rd(){
 21     ll x=0;char c=gc();bool neg=0;
 22     while(c<'0'||c>'9'){if(c=='-') neg=1;c=gc();}
 23     while(c>='0'&&c<='9') x=(x<<1)+(x<<3)+c-'0',c=gc();
 24     return neg?(~x+1):x;
 25 }
 26
 27 struct Node{
 28     int a,b,c,d;
 29     Node(int _a=1,int _b=0,int _c=0,int _d=0){a=_a,b=_b,c=_c,d=_d;}
 30 }val[maxp];
 31 Node operator *(Node x,Node y){
 32     return Node(1ll*x.a*y.a%P,(1ll*x.b*y.a+y.b)%P,(1ll*x.a*y.c+x.c)%P,(1ll*x.b*y.c+x.d+y.d)%P);
 33 }
 34
 35 int N,K,W,dan[maxn],eg[maxn*2][2],egh[maxn],ect;
 36 int ch[maxp][2],stk[maxp],sh,rt[maxn];
 37 int yy[maxn];
 38
 39 inline void adeg(int a,int b){
 40     eg[++ect][0]=b,eg[ect][1]=egh[a],egh[a]=ect;
 41 }
 42
 43 inline int newnode(){
 44     int p=stk[sh--];
 45     assert(sh>=1);
 46     ch[p][0]=ch[p][1]=0;
 47     val[p]=Node();
 48     return p;
 49 }
 50
 51 inline void delall(int &p){
 52     if(!p) return;
 53     delall(ch[p][0]);delall(ch[p][1]);
 54     stk[++sh]=p;p=0;
 55 }
 56
 57 inline void pushdown(int p){
 58     if(!ch[p][0]) ch[p][0]=newnode();
 59     if(!ch[p][1]) ch[p][1]=newnode();
 60     val[ch[p][0]]=val[ch[p][0]]*val[p];
 61     val[ch[p][1]]=val[ch[p][1]]*val[p];
 62     val[p]=Node();
 63 }
 64
 65 void mul(int &p,int l,int r,int x,int y,Node z){
 66     if(!p) p=newnode();
 67     if(x<=l&&r<=y){
 68         val[p]=val[p]*z;
 69     }else{
 70         int m=(l+r)>>1;pushdown(p);
 71         if(x<=m) mul(ch[p][0],l,m,x,y,z);
 72         if(y>=m+1) mul(ch[p][1],m+1,r,x,y,z);
 73     }
 74 }
 75
 76 int merge(int &p,int &q){
 77     if(!p||!q) return p|q;
 78     if(!ch[p][0]&&!ch[p][1]) swap(p,q);
 79     if(!ch[q][0]&&!ch[q][1]){
 80         val[p]=val[p]*Node(val[q].b,0,0,val[q].d);
 81         return p;
 82     }
 83     pushdown(p),pushdown(q);
 84     ch[p][0]=merge(ch[p][0],ch[q][0]);
 85     ch[p][1]=merge(ch[p][1],ch[q][1]);
 86     return p;
 87 }
 88
 89 void dfs(int x,int f,int id){
 90     mul(rt[x],1,W,1,W,Node(0,1,0,0));
 91     for(int i=egh[x];i;i=eg[i][1]){
 92         int b=eg[i][0];if(b==f) continue;
 93         dfs(b,x,id);
 94         merge(rt[x],rt[b]);
 95         delall(rt[b]);
 96     }
 97     mul(rt[x],1,W,1,dan[x],Node(id,0,0,0));
 98     mul(rt[x],1,W,1,W,Node(1,0,1,0));
 99     mul(rt[x],1,W,1,W,Node(1,1,0,0));
100 }
101
102 int query(int p,int l,int r){
103     if(!p) return 0;
104     if(l==r) return val[p].d;
105     int m=(l+r)>>1;pushdown(p);
106     return (query(ch[p][0],l,m)+query(ch[p][1],m+1,r))%P;
107 }
108
109 int fpow(int x,int y){
110     int r=1;
111     while(y){
112         if(y&1) r=1ll*r*x%P;
113         x=1ll*x*x%P,y>>=1;
114     }return r;
115 }
116
117 int l[maxn],tmp[maxn],ans[maxn];
118 void calc(){
119     l[0]=1;
120     for(int i=1;i<=N+1;i++){
121         for(int j=i-1;j>=0;j--){
122             l[j+1]=(l[j+1]+l[j])%P;
123             l[j]=-1ll*i*l[j]%P;
124         }
125     }
126     for(int i=1;i<=N+1;i++){
127         int ib=-fpow(i,P-2);
128         tmp[0]=1ll*l[0]*ib%P;
129         for(int j=1;j<=N;j++){
130             tmp[j]=1ll*(l[j]-tmp[j-1])*ib%P;
131         }
132         int k=0,x=1;
133         for(int j=0;j<=N;j++){
134             k=(1ll*x*tmp[j]+k)%P;
135             x=1ll*x*i%P;
136         }
137         k=1ll*fpow(k,P-2)*yy[i]%P;
138         for(int j=0;j<=N;j++){
139             ans[j]=(1ll*tmp[j]*k+ans[j])%P;
140         }
141     }
142 }
143
144 int main(){
145     //freopen("","r",stdin);
146     N=rd(),K=rd(),W=rd();
147     for(int i=1;i<=N;i++) dan[i]=rd();
148     for(int i=1;i<N;i++){
149         int a=rd(),b=rd();
150         adeg(a,b);adeg(b,a);
151     }
152     for(int i=1;i<maxp-5;i++) stk[++sh]=i;
153
154     for(int i=1;i<=N+1;i++){
155         dfs(1,0,i);
156         yy[i]=query(rt[1],1,W);
157         delall(rt[1]);
158     }
159     calc();
160     int a=0;
161     for(int i=K;i<=N;i++) a=(a+ans[i])%P;
162     printf("%d\n",(a+P)%P);
163     return 0;
164 }

转载于:https://www.cnblogs.com/Ressed/p/10504966.html

luogu4365 秘密袭击 (生成函数+线段树合并+拉格朗日插值)相关推荐

  1. 【九省联考2018】秘密袭击【树形dp】【生成函数】【线段树合并】【多项式插值】

    题意:nnn 个点的带点权的树,点权最大值为 www,求所有连通子图第 kkk 大权值之和模 641236412364123. n,w≤1666n,w\leq 1666n,w≤1666,时限 5s. ...

  2. 线段树合并与分裂维护树上最长上升子序列 + 点分治删点 ---- 2021 牛客多校第一场 C - Cut the tree(详解)

    题目大意: 给你一个树,树上每个点都有一个权值valnodeval_{node}valnode​,路径(u,v)(u,v)(u,v) 上所有点按顺序有序序列,令f(u,v)f(u,v)f(u,v)是这 ...

  3. 线段树分裂与合并 ---- 树上差分 P4556 [Vani有约会]雨天的尾巴 /【模板】线段树合并

    题目链接 解题思路: 首先题目是对u,vu,vu,v这两条路径上面添加一个zzz,然后运用树上点的差分思想,对于分发路径u,vu,vu,v,我们在uuu上+1+1+1,在vvv上+1+1+1,在lca ...

  4. 【线段树合并】解题报告:luogu P4556雨天的尾巴 (树上对点差分 + 动态开点 + 线段树合并)线段树合并模板离线/在线详解

    题目链接:雨天的尾巴 本题本身是一个非常简单的一道树上差分的模板题,但是由于变态的数据范围,我们直接用数组是存不下的(本来使用一颗普通的线段树直接维护最大值即可.但是本题的空间只有128MB,直接按照 ...

  5. 【BZOJ-3681】Arietta 网络流 + 线段树合并

    3681: Arietta Time Limit: 20 Sec  Memory Limit: 64 MB Submit: 182  Solved: 70 [Submit][Status][Discu ...

  6. BZOJ3526[Poi2014]Card——线段树合并

    题目描述 有n张卡片在桌上一字排开,每张卡片上有两个数,第i张卡片上,正面的数为a[i],反面的数为b[i].现在,有m个熊孩子来破坏你的卡片了! 第i个熊孩子会交换c[i]和d[i]两个位置上的卡片 ...

  7. 【BZOJ5461】 【PKUWC2018】—Minimax(线段树合并优化dp)

    传送门 发现其实就是左右2棵子树,左儿子选到某个值的概率就是 选最大值的概率∗右儿子的值比它小的概率选最大值的概率*右儿子的值比它小的概率选最大值的概率∗右儿子的值比它小的概率 +选最小值的概率∗右儿 ...

  8. [BJWC2018]Border 的四种求法(后缀自动机+链分治+线段树合并)

    题目描述 给一个小写字母字符串 S ,q 次询问每次给出 l,r ,求 s[l..r] 的 Border . Border: 对于给定的串 s ,最大的 i 使得 s[1..i] = s[|s|-i+ ...

  9. CF1037H Security——SAM+线段树合并

    又是一道\(SAM\)维护\(endpos\)集合的题,我直接把CF700E的板子粘过来了QwQ 思路 如果我们有\([l,r]\)对应的\(SAM\),只需要在上面贪心就可以了.因为要求的是字典序比 ...

最新文章

  1. 360金融沈赟:只有适配实践的技术才能实现价值掘金
  2. tcpdump抓取mysql语句
  3. python爬虫面试题
  4. docker部署express项目
  5. C++开发的应用方向有哪些?
  6. 计算机二级access数据库考试题型,2016最新计算机二级Access数据库试题及答案
  7. win10无法运行jre java_Windows10系统安装不了jre的解决方法
  8. 深度学习花书+机器学习西瓜书电子版我找到了
  9. 百度网盘获取下载链接
  10. 关于automation服务器不能创建对象
  11. MPM模型及ab压力测试
  12. linux sar 分析,Linux性能测试分析命令_sar
  13. HTML制作导航条的方法
  14. 在Qt中使用OpenGL(二)
  15. 3月13日云栖精选夜读 | Serverless 风暴来袭,前端工程师如何应对?...
  16. 【ModuleNotFoundError 与 ImportError】之 most likely due to a circular import
  17. 对于HTML文档标题居中,导出word 和网页显示 问题
  18. 怎么释放C盘空间?清理C盘空间的4大方法分享!
  19. Tensor (张量) - 神经网络中的数据结构
  20. SAR ADC系列16:CDAC上机实践+作业

热门文章

  1. MacOS中Dock栏的设置和使用技巧,新手必看
  2. 【树莓派学习笔记】六、启用摄像头、实时视频、录像和截图
  3. [算法] vector删除元素
  4. [bash] 打包某目录(可以是绝对路径)下的指定扩展名的文件
  5. 重学java基础第十三课:java帝国的诞生
  6. React开发(127):引入icon的方式
  7. 前端学习(3262):js高级教程(5)数据变量和内存
  8. [html] 在两个iframe之间传递参数的方法有哪些?
  9. [css] 在sass中可以执行布尔运算吗?
  10. 前端学习(2799):实现资讯的结构和列表