为方便区域赛打印pdf模板,所有代码已经搬家到了github中。
目录:
SAM(*)
SA(*)
PAM(*)
树链剖分(*)
01Trie(*)
ACAM(*)
KMP(*)
LCA(*)
主席树(*)
点分治(*)
kd-Tree(*)
斜率优化DP
最大流Dicnic(*)
最小费用最大流(SPFA)(*)
线段树(*)
dfs靠谱找环
靠谱找凸包(*)
tarjan缩点+点双连通(寻割)+边双连通(寻桥)
虚树(*)
圆方树(*)
FFT(*)
SAM+LCT在线动态维护parent树:
#include
#define N 1200005
#define inf 1000000007
using namespace std;
int mask;char s[3000005];
int Q;
string chars;
void gets(int mask){
scanf("%s",s);chars=s;
for(int j=0;j
SAM动态求 出现至少k次本质不同子串个数:
#include
using namespace std;
const int maxn = 25e4+1000;
char s[maxn]; int len,k,n,m; char temp[5];
struct SAM{
int last,cnt,nxt[maxn*2][26],fa[maxn*2],l[maxn*2],num[maxn*2];
int ans;
void init(){
last = cnt=1;
memset(nxt[1],0,sizeof nxt[1]);
fa[1]=l[1]=num[1]=0;
ans=0;
}
int inline newnode(){
cnt++;
memset(nxt[cnt],0,sizeof nxt[cnt]);
fa[cnt]=l[cnt]=num[cnt]=0;
return cnt;
}
void add(int c){
int p = last; int np = newnode();
last = np; l[np] =l[p]+1;
while (p&&!nxt[p][c]){
nxt[p][c] = np;
p = fa[p];
}
if (!p){ fa[np] =1;}
else{
int q = nxt[p][c];
if (l[q]==l[p]+1){fa[np] =q;}
else{
int nq = newnode();
memcpy(nxt[nq],nxt[q],sizeof nxt[q]);
fa[nq] =fa[q]; num[nq] = num[q];
l[nq] = l[p]+1; fa[np] =fa[q] =nq;
while (nxt[p][c]==q){
nxt[p][c]=nq;
p = fa[p];
}
}
}
int temp = last;
while (temp){
if (num[temp]>=k){ break; }
num[temp]++;
if (num[temp]==k){
ans+=l[temp]-l[fa[temp]];
}
temp = fa[temp];
}
}
}sam;
int main(){
while (scanf("%d%d%d",&n,&m,&k)!=EOF){
scanf("%s",s);
len = strlen(s); sam.init();
for (int i=0;i
SAM 字典序第k小串
#include
using namespace std;
const int maxn = 9e4+1000;
int len; char s[maxn];
int cntA[maxn]; vector ans;
struct SAM{
int last,cnt,nxt[maxn*2][26],fa[maxn*2],l[maxn*2];
int rk[maxn*2],num[maxn*2];
void init(){
last = cnt=1;
memset(nxt[1],0,sizeof nxt[1]);
fa[1]=l[1] =0;
}
void add(int c){
int p = last; int np = ++cnt;
last = np; l[np] =l[p]+1;
while (p&&!nxt[p][c]){
nxt[p][c] = np;
p = fa[p];
}
if (!p){ fa[np] =1;}
else{
int q = nxt[p][c];
if (l[q]==l[p]+1){ fa[np] =q; }
else{
int nq = ++cnt;
memcpy(nxt[nq],nxt[q],sizeof nxt[q]);
fa[nq] =fa[q]; l[nq] = l[p]+1;
fa[np] =fa[q] =nq;
while (nxt[p][c]==q){
nxt[p][c]=nq;
p = fa[p];
}
}
}
}
void build (){
for (int i=1;i<=cnt;i++){
cntA[l[i]]++;
}
for (int i=1;i=1;i--){
int x = rk[i];
for (int i=0;i<26;i++){
if (nxt[x][i]){
num[x]+=num[nxt[x][i]];
}
}
}
num[0]=0;
}
inline void print(){
for (char t:ans){
printf("%c",t);
}
printf("\n");
}
void query(int K){
ans.clear();
int now=1; int sum=0;
while (true){
if (sum==K){
print();
return ;
}
int c=0;
int last =0;
while (sum
SA:
SA+Manacher求本质不同回文串个数
#include
using namespace std;
#define rank rk
const int MAX = 2e5+10000;
char ch[MAX];
int cntA[MAX],cntB[MAX],A[MAX],B[MAX],tsa[MAX],rank[MAX],SA[MAX],lc[MAX],h[MAX];
int n,t; int Cas =1;
void init(){
memset(ch,0,sizeof ch);
ch[0]='z'+1;
}
void input(){
scanf("%s",ch+1);
n = strlen(ch+1);
ch[n*2+1]='#';
for (int i=n;i>=1;i--){
ch[i*2] = ch[i];
ch[i*2-1] ='#';
}
n = n*2+1;
ch[n+1]='\0';
}
void get_SA(){
for (int i=0;i<=10000;i++) cntA[i]=0;
for (int i=1;i<=n;i++) cntA[ch[i]]++;
for (int i=1;i<=10000;i++) cntA[i]+=cntA[i-1];
for (int i=n;i>=1;i--) SA[cntA[ch[i]]--] =i;
rank[SA[1]]=1;
for (int i=2;i<=n;i++){
rank[SA[i]]=rank[SA[i-1]];
if (ch[SA[i]]!=ch[SA[i-1]]) rank[SA[i]]++;
}
for (int step = 1;rank[SA[n]]=1;i--) tsa[cntB[B[i]]--] =i;
for (int i=n;i>=1;i--) SA[cntA[A[tsa[i]]]--] = tsa[i];
rank[SA[1]]=1;
for (int i=2;i<=n;i++){
rank[SA[i]]=rank[SA[i-1]];
if (A[SA[i]]!=A[SA[i-1]]||B[SA[i]]!=B[SA[i-1]]) rank[SA[i]]++;
}
}
}
void get_Height(){
for (int i=1,j=0;i<=n;i++){
if (j) j--;
while (ch[i+j]==ch[SA[rank[i]-1]+j])j++;
h[rank[i]]=j;
}
}
void Manacher(){
lc[1]=1; int k=1;
for (int i=2;i<=n;i++){
int p = k+lc[k]-1;
if (i<=p){
lc[i]=min(lc[2*k-i],p-i+1);
}else{ lc[i]=1; }
while (ch[i+lc[i]]==ch[i-lc[i]])lc[i]++;
if (i+lc[i]>k+lc[k])k=i;
}
}
void print(){
printf("%s\n",ch+1);
for (int i=1;i<=n;i++){
printf("%s %d\n",ch+SA[i],lc[SA[i]]);
}
}
void solve(){
get_SA();get_Height();Manacher();
print();
long long res =0; int cnt=0;
for (int i=2;i<=n;i++){
cnt = min(cnt,h[i]);
res+=max(0,lc[SA[i]]-min(h[i],cnt));
if (lc[SA[i]]>cnt){
cnt = lc[SA[i]];
}
}
printf("Case #%d: %I64d\n",Cas++,res/2);
}
int main(){
scanf("%d",&t);
while (t--){
init();
input();
solve();
}
return 0;
}
PAM
求公共回文串个数。
#include
using namespace std;
const int maxn = 2e5+100;
struct PAM{
int nxt[maxn][26],len[maxn],cnt[maxn],fail[maxn];
int S[maxn];int last,p,now;
int newnode(int l){
memset(nxt[p],0,sizeof nxt[p]);
cnt[p]=0;len[p]=l;
return p++;
}
void init(){
p =0;
newnode(0);newnode(-1);
last =0;now =0;
S[now++] =-1;fail[0]=1;
}
inline int get_fail(int x){
int tx =x;
while (S[now-len[tx]-2]!=S[now-1]) tx = fail[tx];
return tx;
}
void add(int c){
S[now++] =c;
int cur = get_fail(last);
if (!nxt[cur][c]){
int tt = newnode(len[cur]+2);
fail[tt] = nxt[get_fail(fail[cur])][c];
nxt[cur][c] =tt;
}
last = nxt[cur][c];cnt[last]++;
}
void count(){
for (int i=p-1;i>=0;i--){
cnt[fail[i]]+=cnt[i];
}
cnt[0]=cnt[1]=0;
}
}pam1,pam2;
long long dfs(int u,int v){
long long res =0;
for (int i=0;i<26;i++){
int uu = pam1.nxt[u][i];
int vv = pam2.nxt[v][i];
if (uu&&vv){
res +=1LL*pam1.cnt[uu]*pam2.cnt[vv];
res+=dfs(uu,vv);
}
}
return res;
}
int T;int Cas=1; int len1,len2;
char s1[maxn],s2[maxn];
int main(){
scanf("%d",&T);
while (T--){
pam1.init();pam2.init();
scanf("%s%s",s1,s2);
len1 = strlen(s1);len2 = strlen(s2);
for (int i=0;i
树链剖分
树链剖分+树状数组:
#include
using namespace std;
const int INF = 0x3f3f3f3f;
const int MAXN = 250000+100;
struct Seg_Tree{
int sm[MAXN<<1];
inline int lowbit(int _x){return _x&(-_x);}
void build (int l,int r){
for (int i=l;i<=r;i++){
add(i,1);
}
}
void add(int x,int val){
while (x<=MAXN){
sm[x]+=val;
x+=lowbit(x);
}
}
int sum(int x){
int res =0;
while (x){
res+=sm[x];
x-=lowbit(x);
}
return res;
}
int query_sum(int l,int r){
return sum(r)-sum(l-1);
}
}tree;
int first[MAXN*2];int nxt[MAXN*2];int des[MAXN*2];
int tpos[MAXN];int deep[MAXN];int top[MAXN];
int fa[MAXN]; int wson[MAXN]; int size[MAXN];
int n,q,tot=0,cnt=0; char s[10];
inline void add(int _u,int _v){
des[++tot] = _v;
nxt[tot] = first[_u];
first[_u] = tot;
}
void input(){
scanf("%d",&n);
for (int i=1;isize[wson[node]]){
wson[node] = v;
}
size[node]+=size[v];
}
}
void dfs2(int node,int father,int chain){
top[node] = chain; tpos[node] = ++cnt;
if (wson[node]){
dfs2(wson[node],node,chain);
}
for (int t = first[node];t;t = nxt[t]){
int v = des[t];
if (v==father||v ==wson[node]){ continue; }
dfs2(v,node,v);
}
}
void init(){
dfs(1,0); dfs2(1,0,1);
tree.build(2,n);
}
int get_sum(int u,int v){
int res =0;
while (top[u]!=top[v]){
if (deep[top[u]]
树链剖分+线段树:
#include
#define N 100005
#define inf 1000000000
using namespace std;
int n,q,a[4*N];
struct Edge{ int u,v,next; }G[N];
int tot=0,head[N];
int size[100005],wson[100005],fa[100005],d[100005],top[100005];
int tpos[100005],pre[100005],cnt=0;
inline void addedge(int u,int v){
G[++tot].u=u;G[tot].v=v;G[tot].next=head[u];head[u]=tot;
G[++tot].u=v;G[tot].v=u;G[tot].next=head[v];head[v]=tot;
}
void dfs1(int u,int f){
size[u]=1;
for (int i=head[u];i;i=G[i].next){
int v=G[i].v;if (v==f)continue;
d[v]=d[u]+1;fa[v]=u;
dfs1(v,u);
size[u]+=size[v];
if (size[v]>size[wson[u]])wson[u]=v;
}
}
void dfs2(int u,int TP){
tpos[u]=++cnt;pre[cnt]=u;top[u]=TP;
if (wson[u])dfs2(wson[u],TP);
for (int i=head[u];i;i=G[i].next){
int v=G[i].v;
if (v==fa[u]||v==wson[u])continue;
dfs2(v,v);
}
}
int sumv[4*N],maxv[4*N];
inline void pushup(int o){
sumv[o]=sumv[o*2]+sumv[o*2+1];
maxv[o]=max(maxv[o*2],maxv[o*2+1]);
}
void build(int o,int l,int r){
int mid=(l+r)/2;
if (l==r){sumv[o]=maxv[o]=a[pre[l]];return;}
build(o*2,l,mid);build(o*2+1,mid+1,r);
pushup(o);
}
void update(int o,int l,int r,int q,int v){
int mid=(l+r)/2;
if (l==r){sumv[o]=maxv[o]=v;return;}
if (q<=mid)update(o*2,l,mid,q,v);
else update(o*2+1,mid+1,r,q,v);
pushup(o);
}
int querysum(int o,int l,int r,int ql,int qr){
int mid=(l+r)/2,ans=0;
if (ql<=l&&r<=qr)return sumv[o];
if (ql<=mid)ans+=querysum(o*2,l,mid,ql,qr);
if (qr>mid)ans+=querysum(o*2+1,mid+1,r,ql,qr);
pushup(o);
return ans;
}
int querymax(int o,int l,int r,int ql,int qr){
int mid=(l+r)/2,ans=-inf;
if (ql<=l&&r<=qr)return maxv[o];
if (ql<=mid)ans=max(ans,querymax(o*2,l,mid,ql,qr));
if (qr>mid)ans=max(ans,querymax(o*2+1,mid+1,r,ql,qr));
pushup(o);
return ans;
}
int qsum(int u,int v){
int ans=0;
while (top[u]!=top[v]){
if (d[top[u]]
01Trie:
可持久化01Trie+DFS序 子树上的点抑或最大值:
#include
using namespace std;
const int MAX = 1e5+100;
int bas[35]; int nxt[MAX<<5][2];
int root[MAX]; int sum[MAX<<5];
int n,q; vectorE[MAX];
int st[MAX],en[MAX],rk[MAX];
int a[MAX]; int cnt; int tot;
void sheet(){
bas[0]=1;
for (int i=1;i<=30;i++){
bas[i] = bas[i-1]<<1;
}
}
void init(){
for (int i=0;i<=n;i++){ E[i].clear(); }
cnt =tot=0;
memset(nxt[0],0,sizeof nxt[0]);
}
void input(){
for (int i=1;i<=n;i++){ scanf("%d",a+i); }
for (int u=2;u<=n;u++){
int v; scanf("%d",&v);
E[u].push_back(v); E[v].push_back(u);
}
}
void dfs(int node ,int father ){
st[node] = ++tot; rk[tot] = node;
for (int des:E[node]){
if(des==father){ continue; }
dfs(des,node);
}
en[node] = tot;
}
int create(){
cnt++;
memset(nxt[cnt],0,sizeof nxt[cnt]);
return cnt;
}
int insert(int rt,int val){
int y = ++cnt; int x = rt; int res = y;
for (int i=30;i>=0;i--){
sum[y] = sum[x]+1;
nxt[y][0] = nxt[x][0]; nxt[y][1] = nxt[x][1];
int t = val&bas[i];
t>>=i;
nxt[y][t] = create();
y = nxt[y][t]; x = nxt[x][t];
}
sum[y] = sum[x]+1;
return res;
}
int query(int l,int r,int val){
int res =0; int x = l; int y = r;
for (int i=30;i>=0;i--){
int t = val&bas[i];
t>>=i;
if (sum[nxt[y][!t]]-sum[nxt[x][!t]]){
y = nxt[y][!t]; x = nxt[x][!t];
res+=bas[i];
}else{
y = nxt[y][t]; x = nxt[x][t];
}
}
return res;
}
void solve(){
dfs(1,0);
for (int i=1;i<=n;i++){
root[i] = insert(root[i-1],a[rk[i]]);
}
while (q--){
int nod,x;
scanf("%d%d",&nod,&x);
printf("%d\n",query(root[st[nod]-1],root[en[nod]],x));
}
}
int main(){
sheet();
while (scanf("%d%d",&n,&q)!=EOF){
init();
input();
solve();
}
return 0;
}
01Trie求区间抑或和的最大值
#include
#include
#include
using namespace std;
const int MAX = 1e6+100;
int bas[35];
const int INF = 2147483645;
struct Trie{
int nxt[MAX<<2][2]; int l[MAX<<2];
int cnt; int ansl,ansr,ansv;
void init(){
cnt =0;
memset(nxt[0],0,sizeof (nxt[0]));
memset(l,0x3f3f3f3f,sizeof(l));
ansv = 0;
}
int create(){
cnt++;
memset(nxt[cnt],0,sizeof (nxt[cnt]));
return cnt;
}
void insert(int id,int x){
int y = 0;
for (int i=30;i>=0;i--){
int t = x&bas[i];
t>>=i;
if (!nxt[y][t]){
nxt[y][t] = create();
}
y = nxt[y][t];
}
l[y] = min(l[y],id);
}
void query(int id,int x){
int y=0; int res =0;
for (int i=30;i>=0;i--){
int t = x&bas[i];
t>>=i;
if (nxt[y][!t]){
y =nxt[y][!t];
res+=bas[i];
}else{
y = nxt[y][t];
}
}
if (res==ansv){
if (l[y]ansv){
ansv = res;
ansl = l[y];
ansr = id;
}
}
void print(int id){
printf("Case #%d:\n%d %d\n",id,ansl+1,ansr);
}
}trie;
void init(){
bas[0] = 1;
for (int i=1;i<=30;i++){
bas[i] = bas[i-1]<<1;
}
}
int main(){
init(); int n,Cas;
scanf("%d",&Cas);
for (int i=1;i<=Cas;i++){
trie.init(); trie.insert(0,0);
scanf("%d",&n);
int sum=0;
for (int j=1;j<=n;j++){
int ai;
scanf("%d",&ai); sum^=ai;
trie.query(j,sum); trie.insert(j,sum);
}
trie.print(i);
}
return 0;
}
AC自动机
ACAM单词统计模板:
#include
using namespace std;
const int maxn = 1e6+100;
char s[maxn];
int n,T;
struct AC{
//不要忘记取过某个单词之后,把标记清了,防止重复统计!!!
int nxt[maxn][26],root,cnt,fail[maxn],val[maxn];
void init(){
root = cnt=0;
memset(nxt[0],0,sizeof nxt[0]);
fail[0]=val[0]=0;
}
inline int create(){
cnt++;
memset(nxt[cnt],0,sizeof nxt[cnt]);
fail[cnt] = val[cnt] = 0;
return cnt;
}
void insert(char word[],int len){
int now = root;
for (int i=0;i Q;
fail[root] = root;
Q.push(root);
while (!Q.empty()){
int q = Q.front();Q.pop();
for (int i=0;i<26;i++){
if (!nxt[q][i])continue;
int son = nxt[q][i];
if (q==root){
fail[son] = root;
}else{
fail[son] = fail[q];
while (fail[son]&&!nxt[fail[son]][i])fail[son] = fail[fail[son]];
if (nxt[fail[son]][i]){
fail[son] = nxt[fail[son]][i];
}
}
Q.push(son);
}
}
}
int query(char word[],int len){
int now = root;
int res=0;
for (int i=0;i
KMP
KMP+DP求最小压缩表示法(最小循环节)
#include
using namespace std;
#define MAXN 8005
#define INF 2147483640
char s[MAXN]; int n;
int dp[MAXN]; int nxt[MAXN];
int nums (int a){
int ans = 0;
while (a)ans++,a/=10;
return ans;
}
void kmp(char ss[]){
memset(nxt,sizeof(nxt),0);
int len = strlen(ss+1);
for (int i=2;i<=len;i++){
nxt[i]=nxt[i-1];
while (nxt[i]&&ss[i]!=ss[nxt[i]+1])nxt[i]=nxt[nxt[i]];
nxt[i]+=(ss[i]==ss[nxt[i]+1]);
}
}
int main(){
scanf("%s",s+1);
n = strlen(s+1);
for (int i=1;i<=n;i++){ dp[i]=INF; }
for (int i=0;i<=n;i++){
kmp(s+i);
for (int j=i+1;j<=n;j++){
int temp = j-i-nxt[j-i];
int recyTime = (j-i)%temp==0?(j-i)/temp:1;
dp[j] = min(dp[j],dp[i]+(j-i)/recyTime+nums(recyTime));
}
}
cout<
KMP求最小循环节 +DP求最小压缩表示
#include
using namespace std;
#define MAXN 8005
#define INF 2147483640
char s[MAXN]; int n;
int dp[MAXN]; int nxt[MAXN];
int nums (int a){
int ans = 0;
while (a)ans++,a/=10;
return ans;
}
void kmp(char ss[]){
memset(nxt,sizeof(nxt),0);
int len = strlen(ss+1);
for (int i=2;i<=len;i++){
nxt[i]=nxt[i-1];
while (nxt[i]&&ss[i]!=ss[nxt[i]+1])nxt[i]=nxt[nxt[i]];
nxt[i]+=(ss[i]==ss[nxt[i]+1]);
}
}
int main(){
scanf("%s",s+1); n = strlen(s+1);
for (int i=1;i<=n;i++){ dp[i]=INF; }
for (int i=0;i<=n;i++){
kmp(s+i);
for (int j=i+1;j<=n;j++){
int temp = j-i-nxt[j-i];
int recyTime = (j-i)%temp==0?(j-i)/temp:1;
dp[j] = min(dp[j],dp[i]+(j-i)/recyTime+nums(recyTime));
}
}
cout<
LCA
倍增LCA:
#include
using namespace std;
const int maxn = 5e5+100;
int first[maxn],nxt[maxn*2],des[maxn*2];
int st[maxn][21];int dep[maxn];
int m,n;int tot=0;int root;
inline int read(){
int re_ =0;
char ch_ = getchar();
while (ch_<'0'||ch_>'9')ch_ = getchar();
while (ch_>='0'&&ch_<='9') re_ = re_*10+ch_-'0',ch_ = getchar();
return re_;
}
inline void addEdge(int x,int y){
tot++;des[tot] =y;
nxt[tot] = first[x];first[x] =tot;
}
inline void input(){
n = read();m = read();
root=read();
for (int i=1;i=0;i--){
if (dep[st[x][i]]>=dep[y]){
x = st[x][i];
}
}
if (x==y)return x;
for (int i=20;i>=0;i--){
if (st[x][i]!=st[y][i]){
x=st[x][i];y=st[y][i];
}
}
return st[x][0];
}
inline void solve(){
int x =read(),y=read();
printf("%d\n",lca(x,y));
}
int main(){
input();
dfs(root,0);
while (m--){solve();}
return 0;
}
主席树
树上主席树
#include
#define l(x) tree[x].L
#define r(x) tree[x].R
using namespace std;
const int maxn = 1e5+1000;
struct Node{int L,R,val;}tree[maxn*40];
int root[maxn];
vector E[maxn];int a[maxn];
int rk[maxn];int pos[maxn];int st[maxn][21];
int dep[maxn];int cnt,m,n;int lastans=0;
void input(){
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++){
scanf("%d",a+i);
rk[i]=i;
}
for (int i=1;i>1;
tree[k].L = build(l,mid);tree[k].R = build (mid+1,r);
return k;
}
int update(int P,int l,int r,int pos,int del){
int k = cnt++;
tree[k].val = tree[P].val+del;
if (l==r) return k;int mid = l+r >>1;
if (pos<=mid){
tree[k].L = update(tree[P].L,l,mid,pos,del);
tree[k].R = tree[P].R;
}else{
tree[k].L = tree[P].L;
tree[k].R = update(tree[P].R,mid+1,r,pos,del);
}
return k;
}
void dfs(int node,int father){
root[node] = update(root[father],1,n,pos[node],1);
st[node][0] =father;dep[node] = dep[father]+1;
for (int i=1;i<=19;i++){
st[node][i] = st[st[node][i-1]][i-1];
if (!st[node][i]){break;}
}
for (vector::iterator it = E[node].begin();it!=E[node].end();++it){
int v = *it;
if (v==father)continue;
dfs(v,node);
}
}
void presolve(){
sort(rk+1,rk+1+n,cmp);
for (int i=1;i<=n;i++){pos[rk[i]] =i;}
root[0] = build(1,n);
dfs(1,0);
}
int lca(int u,int v){
if (dep[u]=0;i--){
if (dep[st[u][i]]>=dep[v]){
u = st[u][i];
}
}
if (u==v){return u;}
for (int i=19;i>=0;i--){
if (st[u][i]!=st[v][i]){
u = st[u][i];
v = st[v][i];
}
}
return st[u][0];
}
int query_kth(int rtx,int rty,int anc,int fanc,int l,int r,int k){
if (l==r)return l;
int mid = l+r>>1;
int temp = tree[l(rtx)].val+tree[l(rty)].val-tree[l(anc)].val-tree[l(fanc)].val;
if (temp>=k)return query_kth(tree[rtx].L,tree[rty].L,tree[anc].L,tree[fanc].L,l,mid,k);
else return query_kth(tree[rtx].R,tree[rty].R,tree[anc].R,tree[fanc].R,mid+1,r,k-temp);
}
int query(int x,int y,int k){
int anc = lca(x,y);
int tmp=query_kth(root[x],root[y],root[anc],root[st[anc][0]],1,n,k);
return a[rk[tmp]];
}
void solve(){
while (m--){
int x,y,k;
scanf("%d%d%d",&x,&y,&k);
x =x^lastans;
lastans = query(x,y,k);
printf("%d",lastans);
if (m){printf("\n");}
}
}
int main(){
input();
presolve();
solve();
return 0;
}
主席树求区间第k值(模板)
#include
using namespace std;
const int maxn=1e5+100;
struct Node{int L,R,val;}tree[maxn*500];
int a[maxn];int rk[maxn];int pos[maxn];
int root[maxn];int cnt,m,n,T;
inline void input(){
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++){
scanf("%d",&a[i]);
rk[i]=i;
}
}
inline void init(){
memset(root,0,sizeof root);
cnt =0;
}
int build (int l,int r){
int k = cnt++;
tree[k].val =0;
if (l==r) return k;
int mid = l+r >>1;
tree[k].L = build (l,mid);tree[k].R = build (mid+1,r);
return k;
}
int update (int P,int l,int r,int ppos,int del){
int k = cnt++;
tree[k].val = tree[P].val +del;
if (l==r) return k;
int mid = l+r >>1;
if (ppos<=mid){
tree[k].L = update(tree[P].L,l,mid,ppos,del);
tree[k].R = tree[P].R;
}else{
tree[k].L = tree[P].L;
tree[k].R = update(tree[P].R,mid+1,r,ppos,del);
}
return k;
}
bool cmp(int x,int y){return a[x]>1;
if (tree[tree[rt].L].val-tree[tree[lt].L].val>=k) return query_kth(tree[lt].L,tree[rt].L,l,mid,k);
else return query_kth(tree[lt].R,tree[rt].R,mid+1,r,k+tree[tree[lt].L].val-tree[tree[rt].L].val);
}
void solve(){
while (m--){
int l,r,k;
scanf("%d%d%d",&l,&r,&k);
printf("%d\n",query_kth(root[l-1],root[r],1,n,k));
}
}
int main(){
scanf("%d",&T);
while (T--){
init();
input();
presolve();
solve();
}
return 0;
}
点分治
求树上包含所有颜色(节点有颜色)的有向路径数:
#include
using namespace std;
const int maxn = 5e4+100;
const int maxk = 12;
int first[maxn],nxt[maxn*2],des[maxn*2],tot;
int a[maxn]; int bas[maxk]; int status[maxn];
bool vis[maxn]; long long cnt[1100];
int sz[maxn],ssz[maxn]; int k,n,maxstatus;
long long ans; int Min,Minid;
const int INF = 0x3f3f3f3f;
void prework(){
bas[0]=1;
for (int i=1;i<=10;i++){
bas[i] =bas[i-1]*2;
}
}
void init(){
tot=ans=0;
memset(vis,0,sizeof vis);
memset(first,0,sizeof first);
}
inline void addEdge(int x_,int y_){
tot++; des[tot] =y_;
nxt[tot]=first[x_]; first[x_]=tot;
}
void input(){
for (int i=1;i<=n;i++){
int flag;
scanf("%d",&flag);
a[i] =bas[flag-1];
}
for (int i=1;issz[node])ssz[node] = sz[v];
}
}
void find_root(int node,int father,int root){
int val = max(sz[root]-sz[node],ssz[node]);
if (val
求路径长度<=K的条数 板子:
#include
#include
#include
using namespace std;
const int MAX = 1e4+100;
const int INF = 0x3f3f3f3f;
int first [MAX*2]; int des[MAX*2];
int len[MAX*2]; int nxt[MAX*2];
int n,k,tot; int a[MAX]; int sum[MAX];
int dp[MAX]; int dis[MAX]; int num,ans;
bool vis[MAX]; int Sum,Min,Minid;
void init(){
memset(first,0,sizeof first);
tot =0; ans =0;
memset(vis,0,sizeof vis);
}
inline void add(int x,int y,int z){
tot++;
des[tot]= y; len[tot] =z;
nxt[tot] = first[x]; first[x] = tot;
}
void input(){
for (int i=1;i
kd-Tree
二维树且第三维有限制的搜索模板:
#include
using namespace std;
typedef long long LL;
const int maxn = 2e5+100;
const LL INF = 0x3f3f3f3f3f3f3f3fLL;
int m,n;
const int demension = 2;
struct Hotel{
int pos[demension],id,c;
}hotel[maxn],kdtree[maxn];
double var[demension];
int split [maxn];int cmpDem;
bool cmp(const Hotel &a,const Hotel &b){
return a.pos[cmpDem]=r)return;
int mid = l+r >>1;
for (int i=0;imaxVar){
maxVar = var[i];
split[mid] =i;
}
}
cmpDem = split[mid];
nth_element(hotel+l,hotel+mid,hotel+r+1,cmp);
build (l,mid-1);build (mid+1,r);
}
int ansIndex;
LL ansDis;
void query(int l,int r,const Hotel& x){
if (l>r)return ;
int mid = l+r >>1;LL dis =0;
for (int i=0;iradius){query(mid+1,r,x);}
}else{
query(mid+1,r,x);
if (ansDis>radius){query(l,mid-1,x);}
}
}
int T;
void input(){
scanf("%d%d",&n,&m);
for (int i=0;i
斜率优化DP:
裸斜率优化DP板子,方程dp[ i ] = min { dp[ j ] + ( sum[ i ]- sum[ j ] )^2 }
#include
using namespace std;
#define ll long long
const int maxn = 5e5+10;
ll dp[maxn],q[maxn],sum[maxn];
ll y(int j,int k)
{return dp[j]+sum[j]*sum[j]-dp[k]-sum[k]*sum[k];}
ll x(int j,int k)
{return 2*(sum[j]-sum[k]);}
ll getdp(int i,int j)
{return dp[j]+(sum[i]-sum[j])*(sum[i]-sum[j]);}
int main()
{
ll n,m;
while(scanf("%I64d %I64d",&n,&m)!=EOF)
{
for(int i=1;i<=n;i++)
scanf("%I64d",&sum[i]);
sum[0]=dp[0]=0;
for(int i=1;i<=n;i++)
sum[i]+=sum[i-1];
int head=0,tail=0;
q[tail++]=0;
for(int i=1;i<=n;i++)
{
while(head+1
树上斜率DP,重点在于恢复队列元素,方程:dp[ i ] = min{ dp[ j ] + ( sum[ i ]- sum[ j ] )^2 } +p
#include
using namespace std;
const int maxn = 1e5+100;
typedef long long LL ;
int first[maxn],nxt[maxn*2],des[maxn*2],len[maxn*2],tot;
LL dp[maxn],sum[maxn];
int q[maxn],l,r;int T;
int n,p;
struct Node{
int pos,val;
Node (int pos_,int val_):pos(pos_),val(val_){}
};
inline LL x(int k,int j){
return 2LL*(sum[k]-sum[j]);
}
inline LL y(int k,int j){
return dp[k]+sum[k]*sum[k]-dp[j]-sum[j]*sum[j];
}
inline LL getdp(int i,int j){
return dp[j]+(sum[i]-sum[j])*(sum[i]-sum[j])+p;
}
inline void addEdge(int x,int y,int z){
tot++;
des[tot] =y;len[tot] = z;
nxt[tot] = first[x];first[x] =tot;
}
void init(){
memset(first,0,sizeof first);
tot =0;
}
void input(){
scanf("%d%d",&n,&p);
for (int i=0;i q2;
while (l+1=sum[node]*x(q[l],q[l+1])){
q2.emplace_back(Node(l,q[l]));
l++;
}
if (node!=1) dp[node] = getdp(node,q[l]);
while (l+1=y(q[r-1],node)*x(q[r-2],q[r-1])){
q2.emplace_back(Node(r-1,q[r-1]));
r--;
}
q[r++] = node;
int nowl = l,nowr = r;
for (int t = first[node];t;t=nxt[t]){
int v = des[t];int w = len[t];
if (v==father)continue;
l = nowl;r = nowr;
sum[v] = sum[node]+w;
dfs(v,node);
}
for (Node temp : q2){
q[temp.pos] = temp.val;
}
}
void solve(){
dp[1] = -p;
l =r =0;
dfs(1,0);
LL ans =0;
for (int i=1;i<=n;i++){ans = max(ans,dp[i]);}
cout<
最大流
Dicnic模板
#include
using namespace std;
const int maxn = 205;
const int INF = 0x3f3f3f3f;
int first[maxn],nxt[maxn*2],des[maxn*2],c[maxn*2],tot;
int dep[maxn];int m,n,ss,tt;
void init(){
memset(first,-1,sizeof first);
tot =-1;
}
inline void addEdge(int u,int v,int w){
tot++;
des[tot] = v;c[tot] =w;
nxt[tot] = first[u];first[u] = tot;
}
void input(){
for (int i=0;i Q;Q.push(ss);
while (!Q.empty()){
int q = Q.front();Q.pop();
for (int t = first[q];t!=-1;t= nxt[t]){
int v = des[t],cx = c[t];
if (dep[v]==-1&&cx){
dep[v] = dep[q]+1;
Q.push(v);
}
}
}
return dep[tt]!=-1;
}
int dfs(int node,int now){
if (node==tt)return now;
int res =0;
for (int t = first[node];t!=-1&&res
最小费用最大流
来回最短路&双向边&每个方向的边只能用一次(模板)
#include
#include
#include
#include
#include
using namespace std;
const int maxn = 2000+50;
const int maxm = 20000+50;
const int INF = 0x3f3f3f3f;
int m,n;
int first[maxn],from[maxm*2],des[maxm*2],nxt[maxm*2],cost[maxm*2],flow[maxm*2],tot;
int dis[maxn],pre[maxn];
bool in[maxn];int ss,tt;
inline void addE(int x,int y,int f,int c){
tot++;
from[tot] =x;des[tot] =y;
flow[tot] =f;cost[tot] =c;
nxt[tot] = first[x];first[x] = tot;
}
inline void addEdge(int x,int y,int f,int c){
addE(x,y,f,c);addE(y,x,0,-c);
}
void input(){
scanf("%d%d",&n,&m);
tot =-1;
memset(first,-1,sizeof first);
for (int i=0;i Q;Q.push(ss);
while (!Q.empty()){
int q = Q.front();
Q.pop();
in[q] = 0;
for (int t = first[q];t!=-1;t = nxt[t]){
int v = des[t];
int len = cost[t];
int cx = flow[t];
if (cx&&dis[v]>dis[q]+len){
dis[v] = dis[q]+len;
pre[v] = t;
if (!in[v]){
Q.push(v);in[v] = 1;
}
}
}
}
return pre[tt]!=-1;
}
void solve(){
ss =0;tt=n;
int totflow =0,totcost =0,nowflow =0,nowcost =0;
while (spfa()){
nowcost =0;
nowflow = INF;
int now =pre[tt];
while (now!=-1){
nowflow = min(nowflow,flow[now]);
now = pre[from[now]];
}
now = pre[tt];
while (now!=-1){
flow[now] -= nowflow;
flow[now^1] += nowflow;
nowcost +=cost[now];
now = pre[from[now]];
}
nowcost*=nowflow;
totflow +=nowflow;
totcost +=nowcost;
}
cout<
线段树
区间修改,区间求和
#include
using namespace std;
const int maxn = 1e5+100;
typedef long long LL;
int a[maxn];
struct Seg_Tree{
LL val[maxn*4];LL lazy[maxn*4];
inline void Up(int x){val[x] = val[x<<1]+val[x<<1|1];}
inline void Down(int x,int l,int mid,int r){
if (lazy[x]){
val[x<<1] += 1LL*lazy[x]*(mid-l+1);
val[x<<1|1] += 1LL*lazy[x]*(r-mid);
lazy[x<<1]+= lazy[x];
lazy[x<<1|1] += lazy[x];
lazy[x] =0;
}
}
void build (int x,int l,int r){
lazy[x] =0;
if (l==r){val[x] = a[l];return ;}
int mid = l+r >>1;
build (x<<1,l,mid);build (x<<1|1,mid+1,r);
Up(x);
}
void add(int x,int l,int r,int L,int R,int del){
if (l>R||r>1;
Down(x,l,mid,r);
add(x<<1,l,mid,L,R,del);add(x<<1|1,mid+1,r,L,R,del);
Up(x);
}
LL query_Sum(int x,int l,int r,int L,int R){
if (l>R||r>1;
Down(x,l,mid,r);
return query_Sum(x<<1,l,mid,L,R)+query_Sum(x<<1|1,mid+1,r,L,R);
}
}tree;
char opt[5];
int m,n;
int main(){
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++){
scanf("%d",a+i);
}
tree.build(1,1,n);
while (m--){
int l,r,v;
scanf("%s%d%d",opt,&l,&r);
if (opt[0]=='Q'){
printf("%I64d\n",tree.query_Sum(1,1,n,l,r));
}else if (opt[0]=='C'){
scanf("%d",&v);
tree.add(1,1,n,l,r,v);
}
}
return 0;
}
二位线段树,单点修改,二维最大值查询
#include>1;
Build_2(l,mid,deep,rt<<1);
Build_2(mid+1,r,deep,rt<<1|1);
}
void Build(int l,int r,int rt) // 建x轴方向线段树(一维);
{
Build_2(0,1000,rt,1);
if(l==r) return;
int mid=(l+r)>>1;
Build(l,mid,rt<<1);
Build(mid+1,r,rt<<1|1);
}
void Insert_2(int act,float love,int l,int r,int deep,int rt) // y轴方向更新数据;(二维)
{
seg[deep][rt]=max(love,seg[deep][rt]);
if(l==r) return;
int mid=(l+r)>>1;
if(act<=mid) Insert_2(act,love,l,mid,deep,rt<<1);
else Insert_2(act,love,mid+1,r,deep,rt<<1|1);
seg[deep][rt]=max(seg[deep][rt<<1],seg[deep][rt<<1|1]);
}
void Insert(int h,int act,float love,int l,int r,int rt) // x轴,一维;
{
Insert_2(act,love,0,1000,rt,1);
if(l==r) return;
int mid=(l+r)>>1;
if(h<=mid) Insert(h,act,love,l,mid,rt<<1);
else Insert(h,act,love,mid+1,r,rt<<1|1);
}
float Query_2(int L,int R,int l,int r,int rt,int deep) // 查询,y轴,二维;
{
if(L<=l&&R>=r) return seg[deep][rt];
int mid=(l+r)>>1;
if(R<=mid) return Query_2(L,R,l,mid,rt<<1,deep);
else if(L>mid) return Query_2(L,R,mid+1,r,rt<<1|1,deep);
else return max(Query_2(L,R,l,mid,rt<<1,deep),Query_2(L,R,mid+1,r,rt<<1|1,deep));
}
float Query(int h1,int h2,int L,int R,int l,int r,int rt) // x轴,一维;
{
if(h1<=l&&h2>=r) return Query_2(L,R,0,1000,1,rt);
int mid=(l+r)>>1;
if(h2<=mid) return Query(h1,h2,L,R,l,mid,rt<<1);
else if(h1>mid) return Query(h1,h2,L,R,mid+1,r,rt<<1|1);
else return max(Query(h1,h2,L,R,l,mid,rt<<1),Query(h1,h2,L,R,mid+1,r,rt<<1|1));
}
int main(){
int n;
while(~scanf("%d",&n)&&n){
Build(100,200,1);
char ch[5];
while(n--){
scanf("%s",&ch);
if(ch[0]=='I'){
int h;
float x,y;
scanf("%d%f%f",&h,&x,&y);
Insert(h,(int)(x*10),y,100,200,1);
}else{
int h1,h2; float x1,x2;
scanf("%d%d%f%f",&h1,&h2,&x1,&x2);
if(h1>h2){ int temp=h1; h1=h2;h2=temp; }
if(x1>x2){ float temp=x1;x1=x2;x2=temp; }
float ans=Query(h1,h2,(int)(x1*10),(int)(x2*10),100,200,1);
if(ans==-1.0) printf("-1\n");
else printf("%.1lf\n",ans);
}
}
}
return 0;
}
题目:有向图中最多删掉一条边,是否可以成为DAG
#include
using namespace std;
const int maxn = 505;
const int maxm = 100005;
int first[maxn],nxt[maxm],des[maxm],tot;
int vis[maxn];
int m,n;vector cir;
stack > stk;
inline void addEdge(int u,int v){
tot++;des[tot] =v;
nxt[tot] = first[u];first[u] = tot;
}
void input(){
scanf("%d%d",&n,&m);
for (int i=0;i
靠谱找凸包(dis注意精度,注意n=1和n=2特判)
#include
using namespace std;
typedef long long LL;
const int maxn = 1005;
#define M_PI 3.1415926535
struct Node{int x,y;};
int st[maxn],top; Node a[maxn];
int rk[maxn];int n,T,l;
LL cross(const Node &a,const Node &b,const Node &c){
return 1LL*(b.x-a.x)*(c.y-a.y)-1LL*(c.x-a.x)*(b.y-a.y);
}
LL cross(int x,int y,int z){return cross(a[x],a[y],a[z]);}
double dis(const Node &a,const Node &b){
return sqrt(1.0*(a.x-b.x)*(a.x-b.x)+1.0*(a.y-b.y)*(a.y-b.y));
}
bool cmp(int x,int y){
LL m = cross(a[rk[0]],a[x],a[y]);
if (m>0)return 1;
else if (m==0&&dis(a[rk[0]],a[x])<=dis(a[rk[0]],a[y]))return 1;
else return 0;
}
void solve(){
scanf("%d%d",&n,&l);
for (int i=0;i
缩点+拓扑找出度为零的最小点集
#include
using namespace std;
const int maxn = 1e5+100;
int m,n,h;int t[maxn];
int first[maxn*2],nxt[maxn*2],des[maxn*2],tot;
int dfn[maxn],low[maxn],dft;bool d[maxn];
int flag[maxn],cnt[maxn],scc;stack stk;
inline void add(int x,int y){
tot++;des[tot] =y;
nxt[tot] = first[x];first[x] =tot;
}
void tar(int node){
dfn[node] = low[node] = ++dft;
stk.push(node);
for (int t = first[node];t;t=nxt[t]){
int v = des[t];
if (!dfn[v])tar(v);
low[node] = min(low[node],low[v]);
}
if (dfn[node]==low[node]){
scc++;
while (true){
int temp = stk.top();
flag[temp]=scc;
cnt[scc]++;stk.pop();
if (temp==node)break;
}
}
}
int main(){
scanf("%d%d%d",&n,&m,&h);
for (int i=1;i<=n;i++){scanf("%d",t+i);}
for (int i=0;i
统计联通分量点数和边数
#include
using namespace std;
const int maxn = 1e5+100;
int first[maxn],nxt[maxn*2],from[maxn*2],des[maxn*2],isBrige[maxn*2],tot;
int dfn[maxn],low[maxn],dfs_clock;
int cnt_e[maxn],cnt_n[maxn];int bcc_cnt;
bool ok[maxn];vector ans;int m,n;
inline void addEdge(int x,int y){
tot++;
des[tot] =y;from[tot] =x;
nxt[tot] = first[x];first[x] = tot;
}
void input(){
cin>>n>>m;
for (int i=0;i
连通分量中点数=边数=>整个分量为无向图中一个独立的简单环。
#include
using namespace std;
const int maxn = 1e5+100;
int first[maxn],des[maxn*2],nxt[maxn*2],tot;
int bcc_cnt,cnt_n[maxn],cnt_e[maxn],bcc_no[maxn];
int dfn[maxn],low[maxn],dfs_clock;
int st[maxn*2],top;bool ok[maxn];
vector ans;vector temp;
int m,n;
inline void addEdge(int x,int y){
tot++;des[tot] = y;
nxt[tot] = first[x];first[x] = tot;
}
void input(){
cin>>n>>m;
for (int i=0;i=dfn[u]){
bcc_cnt++;ok[bcc_cnt] = true;
temp.clear();
while (true){
int tt = st[--top];
temp.push_back((tt+1)/2);
if (bcc_no[des[tt]]!=bcc_cnt){
bcc_no[des[tt]] = bcc_cnt;
cnt_n[bcc_cnt]++;
}else{
ok[bcc_cnt] = false;
}
cnt_e[bcc_cnt]++;
if (tt==t){
break;
}
}
if (ok[bcc_cnt]&&temp.size()>1){
for (int i=0;i
虚树
给出有根带边权树,每次询问:删除边使得根与询问点集不联通,最小化边权之和。
#include
using namespace std;
typedef long long LL;
const int maxn = 25e4+100;
const LL INF = 0x3f3f3f3f3f3f3f3fLL;
int first[maxn],des[maxn*2],nxt[maxn*2],tot;
int n,m;
LL dp[maxn],leng[maxn*2], len[maxn];
int vis[maxn],dep[maxn],fa[maxn];
int sz[maxn],wson[maxn],ttop[maxn],tfa[maxn];int k,h[maxn];
int stk[maxn],top;int l[maxn],r[maxn],dfs_clock;
inline void addEdge(int x,int y,int w){
tot++;
des[tot] = y;leng[tot] = w;
nxt[tot] = first[x];first[x] = tot;
}
void dfs(int u,int fath){
l[u] = ++dfs_clock;sz[u]=1;
for (int t = first[u];t;t=nxt[t]){
int v = des[t];
if (v==fath)continue;
LL w = leng[t];
dep[v] = dep[u] + 1;tfa[v]=u;
len[v] = min(len[u],w);
dfs(v,u);sz[u]+=sz[v];
if (sz[v]>sz[wson[u]]){wson[u] = v;}
}
r[u]=dfs_clock ;
}
void dfs2(int u,int chain){
ttop[u]=chain;
if (wson[u])dfs2(wson[u],chain);
for (int t = first[u];t;t=nxt[t]){
int v = des[t];
if (v==tfa[u]||v==wson[u])continue;
dfs2(v,v);
}
}
int lca(int x,int y){
while (ttop[x]!=ttop[y]){
if (dep[ttop[x]]r[stk[top-1]])top--;
fa[h[i]] = stk[top-1];
stk[top++] =h[i];
}
for (int i=k-1;i>=0;i--){
if (vis[h[i]]==2)dp[h[i]] = min(dp[h[i]],len[h[i]]);
else dp[h[i]] = len[h[i]];
dp[fa[h[i]]]+=dp[h[i]];
}
printf("%lld\n",dp[1]);
for (int i=0;i
dp求直径(最长的最短路)
#include
#define pb(x) push_back(x)
using namespace std;
const int maxn = 1e5+100;
vectorE1[maxn],ET[2*maxn],LenT[2*maxn];
int dfn[maxn],fa[2*maxn],len[maxn*2],dfs_clock;
bool inCircle[maxn];
int m,n,ans,N;int dp[maxn][2];
int Q[maxn],head,tail,Max[maxn*2];;
inline void addEdge1(int x,int y){E1[x].pb(y);}
inline void addEdgeT(int x,int y,int w){ET[x].pb(y);LenT[x].pb(w);}
void input(){
scanf("%d%d",&n,&m);N=n;
for (int i=0;i=dp[x][0]){
dp[x][1] = dp[x][0];
dp[x][0]= w;
}else if (w>dp[x][1]){
dp[x][1] = w;
}
}
void work(int squareU){
head = 1;tail = 0;
int length = len[squareU];
for (int i=0;i=i+1-length/2){
ans = max(ans,dp[v][0]+i+1+Q[head]);
}
while (head<=tail&&Q[tail]N){work(u);}
else{ans = max(ans,dp[u][0]+dp[u][1]);}
}
int main(){
input();
tarjan(1);dfs(1);
cout<
FFT
//
// Created by calabash_boy on 18-6-18.
//
#include
using namespace std;
namespace fft {
//attention data type
typedef long long type;
typedef double db;
struct cp {
db x, y;
cp() { x = y = 0; }
cp(db x, db y) : x(x), y(y) {}
};
cp operator+(cp a, cp b) { return cp(a.x + b.x, a.y + b.y); }
cp operator-(cp a, cp b) { return cp(a.x - b.x, a.y - b.y); }
cp operator*(cp a, cp b) { return cp(a.x * b.x - a.y * b.y, a.x * b.y + a.y * b.x); }
cp conj(cp a) { return cp(a.x, -a.y); }
type base = 1;
vector roots = {{0, 0}, {1, 0}};
vector rev = {0, 1};
const db PI = acosl(-1.0);
void ensure_base(type nbase) {
if (nbase <= base) {
return;
}
rev.resize(static_cast(1 << nbase));
for (type i = 0; i < (1 << nbase); i++) {
rev[i] = (rev[i >> 1] >> 1) + ((i & 1) << (nbase - 1));
}
roots.resize(static_cast(1 << nbase));
while (base < nbase) {
db angle = 2 * PI / (1 << (base + 1));
for (type i = 1 << (base - 1); i < (1 << base); i++) {
roots[i << 1] = roots[i];
db angle_i = angle * (2 * i + 1 - (1 << base));
roots[(i << 1) + 1] = cp(cos(angle_i), sin(angle_i));
}
base++;
}
}
void fft(vector &a, type n = -1) {
if (n == -1) {
n = a.size();
}
assert((n & (n - 1)) == 0);
type zeros = __builtin_ctz(n);
ensure_base(zeros);
type shift = base - zeros;
for (type i = 0; i < n; i++) {
if (i < (rev[i] >> shift)) {
swap(a[i], a[rev[i] >> shift]);
}
}
for (type k = 1; k < n; k <<= 1) {
for (type i = 0; i < n; i += 2 * k) {
for (type j = 0; j < k; j++) {
cp z = a[i + j + k] * roots[j + k];
a[i + j + k] = a[i + j] - z;
a[i + j] = a[i + j] + z;
}
}
}
}
vector fa, fb;
vector multiply(vector &a, vector &b) {
type need = a.size() + b.size() - 1;
type nbase = 0;
while ((1 << nbase) < need) nbase++;
ensure_base(nbase);
type sz = 1 << nbase;
if (sz > (type) fa.size())
fa.resize(static_cast(sz));
for (type i = 0; i < sz; i++) {
type x = (i < (type) a.size() ? a[i] : 0);
type y = (i < (type) b.size() ? b[i] : 0);
fa[i] = cp(x, y);
}
fft(fa, sz);
cp r(0, -0.25 / sz);
for (type i = 0; i <= (sz >> 1); i++) {
type j = (sz - i) & (sz - 1);
cp z = (fa[j] * fa[j] - conj(fa[i] * fa[i])) * r;
if (i != j) {
fa[j] = (fa[i] * fa[i] - conj(fa[j] * fa[j])) * r;
}
fa[i] = z;
}
fft(fa, sz);
vector res(static_cast(need));
for (type i = 0; i < need; i++) {
res[i] = fa[i].x + 0.5;
}
return res;
}
vector multiply_mod(vector &a, vector &b, type m, type eq = 0) {
type need = a.size() + b.size() - 1;
type nbase = 0;
while ((1 << nbase) < need) nbase++;
ensure_base(nbase);
type sz = 1 << nbase;
if (sz > (type) fa.size()) {
fa.resize(static_cast(sz));
}
for (type i = 0; i < (type) a.size(); i++) {
type x = (a[i] % m + m) % m;
fa[i] = cp(x & ((1 << 15) - 1), x >> 15);
}
fill(fa.begin() + a.size(), fa.begin() + sz, cp {0, 0});
fft(fa, sz);
if (sz > (type) fb.size()) {
fb.resize(static_cast(sz));
}
if (eq) {
copy(fa.begin(), fa.begin() + sz, fb.begin());
} else {
for (type i = 0; i < (type) b.size(); i++) {
type x = (b[i] % m + m) % m;
fb[i] = cp(x & ((1 << 15) - 1), x >> 15);
}
fill(fb.begin() + b.size(), fb.begin() + sz, cp {0, 0});
fft(fb, sz);
}
db ratio = 0.25 / sz;
cp r2(0, -1);
cp r3(ratio, 0);
cp r4(0, -ratio);
cp r5(0, 1);
for (type i = 0; i <= (sz >> 1); i++) {
type j = (sz - i) & (sz - 1);
cp a1 = (fa[i] + conj(fa[j]));
cp a2 = (fa[i] - conj(fa[j])) * r2;
cp b1 = (fb[i] + conj(fb[j])) * r3;
cp b2 = (fb[i] - conj(fb[j])) * r4;
if (i != j) {
cp c1 = (fa[j] + conj(fa[i]));
cp c2 = (fa[j] - conj(fa[i])) * r2;
cp d1 = (fb[j] + conj(fb[i])) * r3;
cp d2 = (fb[j] - conj(fb[i])) * r4;
fa[i] = c1 * d1 + c2 * d2 * r5;
fb[i] = c1 * d2 + c2 * d1;
}
fa[j] = a1 * b1 + a2 * b2 * r5;
fb[j] = a1 * b2 + a2 * b1;
}
fft(fa, sz);
fft(fb, sz);
vector res(static_cast(need));
for (type i = 0; i < need; i++) {
long long aa = fa[i].x + 0.5;
long long bb = fb[i].x + 0.5;
long long cc = fa[i].y + 0.5;
res[i] = (aa + ((bb % m) << 15) + ((cc % m) << 30)) % m;
}
return res;
}
vector square_mod(vector &a, type m) {
return multiply_mod(a, a, m, 1);
}
};
const int maxn = 2e5+100;
int n,x;
int a[maxn],sum[maxn];
int cnt[maxn];
vector A,B,C;
//example:
//f[i] = number of subsequences whose occurence of 1 is i.
//f[i] = \sum_{cnt[j]*cnt[j-i]}
int main(){
scanf("%d%d",&n,&x);
cnt[0]=1;
for (int i=1;i<=n;i++){
scanf("%d",a+i);
sum[i] =sum[i-1];
if(a[i]>=1;
for (int i=n*2;i<=n*3;i++){
cout<