ACM模板(個人程式碼集整理)(持續更新)
所有程式碼已經搬家到了github中。
目錄:
SAM(*)
SA(*)
PAM(*)
樹鏈剖分(*)
01Trie(*)
ACAM(*)
KMP(*)
LCA(*)
主席樹(*)
點分治(*)
kd-Tree(*)
斜率優化DP
最大流Dicnic(*)
最小費用最大流(SPFA)(*)
線段樹(*)
dfs靠譜找環
靠譜找凸包(*)
tarjan縮點+點雙連通(尋割)+邊雙連通(尋橋)
虛樹(*)
圓方樹(*)
FFT(*)
SAM+LCT線上動態維護parent樹:
#include<bits/stdc++.h> #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<chars.length();j++){ mask=(mask*131+j)%chars.length(); char t=chars[j]; chars[j]=chars[mask]; chars[mask]=t; } } struct Link_Cut_Tree{ int top,fa[N],c[N][2],val[N],tag[N],q[N]; inline void add(int x,int y){if(x)tag[x]+=y,val[x]+=y;} inline void pushdown(int x){ int l=c[x][0],r=c[x][1]; if(tag[x]){ add(l,tag[x]);add(r,tag[x]); tag[x]=0; } } inline bool isroot(int x){return c[fa[x]][0]!=x&&c[fa[x]][1]!=x;} inline void rotate(int x){ int y=fa[x],z=fa[y],l,r; if(c[y][0]==x)l=0;else l=1;r=l^1; if(!isroot(y)){if(c[z][0]==y)c[z][0]=x;else c[z][1]=x;} fa[x]=z;fa[y]=x;fa[c[x][r]]=y; c[y][l]=c[x][r];c[x][r]=y; } inline void splay(int x){ int top=1;q[top]=x; for(int i=x;!isroot(i);i=fa[i])q[++top]=fa[i]; for(int i=top;i;i--)pushdown(q[i]); while(!isroot(x)){ int y=fa[x],z=fa[y]; if(!isroot(y)){ if((c[z][0]==y)^(c[y][0]==x))rotate(x); else rotate(y); }rotate(x); } } void access(int x){for(int t=0;x;t=x,x=fa[x])splay(x),c[x][1]=t;} inline void link(int x,int y){fa[x]=y;access(y);splay(y);add(y,val[x]);} inline void cut(int x){ access(x);splay(x);add(c[x][0],-val[x]); fa[c[x][0]]=0;c[x][0]=0; } }T; struct Suffix_AutoMaton{ int l[N],fa[N],ch[N][26]; int cnt,last; Suffix_AutoMaton(){cnt=1;last=1;} void ins(int c){ int p=last,np=++cnt;last=np;T.val[np]=1;l[np]=l[p]+1; for(;p&&!ch[p][c];p=fa[p])ch[p][c]=np; if(!p)fa[np]=1,T.link(np,1); else{ int q=ch[p][c]; if(l[p]+1==l[q])fa[np]=q,T.link(np,q); else{ int nq=++cnt;l[nq]=l[p]+1; memcpy(ch[nq],ch[q],sizeof(ch[q])); fa[nq]=fa[q];T.link(nq,fa[q]); fa[np]=fa[q]=nq; T.cut(q);T.link(q,nq);T.link(np,nq); for(;ch[p][c]==q;p=fa[p])ch[p][c]=nq; } } } void build(){ scanf("%s",s);int len=strlen(s); for(int i=0;i<len;i++)ins(s[i]-'A'); } int query(){ gets(mask); int p=1;int len=chars.length(); for(int i=0;i<len;i++)if(!(p=ch[p][chars[i]-'A']))return 0; T.splay(p); return T.val[p]; } void add(){ gets(mask);int len=chars.length(); for(int i=0;i<len;i++)ins(chars[i]-'A'); } }sam; int main(){ scanf("%d",&Q);sam.build(); while(Q--){ scanf("%s",s); if(*s=='A')sam.add(); else{ int ans=sam.query(); printf("%d\n",ans); mask^=ans; } } return 0; }
SAM動態求 出現至少k次本質不同子串個數:
#include<bits/stdc++.h> 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<len;i++){ sam.add(s[i]-'a'); } while (m--){ int flag; scanf("%d",&flag); if (flag==1){ scanf("%s",temp); sam.add(temp[0]-'a'); }else{ printf("%d\n",sam.ans); } } } return 0; }
SAM 字典序第k小串
#include<bits/stdc++.h> using namespace std; const int maxn = 9e4+1000; int len; char s[maxn]; int cntA[maxn]; vector<char> 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<maxn-5;i++){ cntA[i]+=cntA[i-1]; } for (int i=1;i<=cnt;i++){ rk[cntA[l[i]]--] =i; } for (int i=1;i<=cnt;i++){ num[i]=1; } for (int i=cnt;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<K){ sum+=num[nxt[now][c]]; c++; assert(c<27); } c--; sum-=num[nxt[now][c]]; now = nxt[now][c]; ans.push_back('a'+c); sum++; } } }sam; int main(){ int Q; scanf("%s%d",s,&Q); sam.init(); int le = strlen(s); for (int i=0;i<le;i++){ sam.add(s[i]-'a'); } sam.build(); while (Q--){ int x; scanf("%d",&x); sam.query(x); } return 0; }
SA:
SA+Manacher求本質不同迴文串個數
#include<bits/stdc++.h>
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]]<n;step<<=1){
for (int i=0;i<=n;i++)cntA[i]=cntB[i]=0;
for (int i=1;i<=n;i++){
cntA[A[i]=rank[i]]++;
cntB[B[i]=(i+step<=n)?rank[i+step]:0]++;
}
for (int i=1;i<=n;i++) cntA[i]+=cntA[i-1],cntB[i]+=cntB[i-1];
for (int i=n;i>=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<bits/stdc++.h>
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<len1;i++){
pam1.add(s1[i]-'a');
}
for (int i=0;i<len2;i++){
pam2.add(s2[i]-'a');
}
pam1.count();pam2.count();
printf("Case #%d: %I64d\n",Cas++,dfs(0,0)+dfs(1,1));
}
return 0;
}
樹鏈剖分
樹鏈剖分+樹狀陣列:
#include<bits/stdc++.h>
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;i<n;i++){
int u,v; scanf("%d%d",&u,&v);
add(u,v); add(v,u);
}
}
void dfs(int node,int father){
deep[node] = deep[father]+1;
fa[node] = father; size[node] =1;
for (int t = first[node];t;t = nxt[t]){
int v = des[t];
if (v==father){ continue; }
dfs(v,node);
if (size[v]>size[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]]<deep[top[v]]){ swap(u,v); }
res+= tree.query_sum(tpos[top[u]],tpos[u]);
u = fa[top[u]];
}
if (deep[u]<deep[v]){ swap(u,v); }
res += tree.query_sum(tpos[v],tpos[u]);
return res;
}
void modify(int u,int v){
if (fa[u]!=v){ swap(u,v); }
tree.add(tpos[u],-1);
}
void solve(){
scanf("%d",&q);
q+=n-1;
while (q--){
scanf("%s",s);
if (s[0]=='W'){
int x;
scanf("%d",&x);
printf("%d\n",get_sum(1,x));
}else{
int x,y;
scanf("%d%d",&x,&y);
modify(x,y);
}
}
}
int main(){
input();
init();
solve();
return 0;
}
樹鏈剖分+線段樹:
#include<bits/stdc++.h>
#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]]<d[top[v]])swap(u,v);
ans+=querysum(1,1,n,tpos[top[u]],tpos[u]);
u=fa[top[u]];
}
if (d[u]<d[v])swap(u,v);
ans+=querysum(1,1,n,tpos[v],tpos[u]);
return ans;
}
int qmax(int u,int v){
int ans=-inf;
while (top[u]!=top[v]){
if (d[top[u]]<d[top[v]])swap(u,v);
ans=max(ans,querymax(1,1,n,tpos[top[u]],tpos[u]));
u=fa[top[u]];
}
if (d[u]<d[v])swap(u,v);
ans=max(ans,querymax(1,1,n,tpos[v],tpos[u]));
return ans;
}
int main(){
memset(head,0,sizeof(head));
memset(a,0,sizeof(a));
scanf("%d",&n);
for (int i=1;i<n;i++){
int u,v;
scanf("%d%d",&u,&v);
addedge(u,v);
}
for (int i=1;i<=n;i++)scanf("%d",&a[i]);
d[1]=1;fa[1]=1;dfs1(1,-1);dfs2(1,1);build(1,1,n);
scanf("%d",&q);
while (q--){
int x,y;
char s[10];
scanf("%s%d%d",s,&x,&y);
if (s[1]=='H')update(1,1,n,tpos[x],y);
if (s[1]=='M')printf("%d\n",qmax(x,y));
if (s[1]=='S')printf("%d\n",qsum(x,y));
}
return 0;
}
01Trie:
可持久化01Trie+DFS序 子樹上的點抑或最大值:
#include<bits/stdc++.h>
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; vector<int>E[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<stdio.h>
#include<cstring>
#include<algorithm>
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]<ansl){
ansl = l[y]; ansr = id;
}
}else if (res>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<bits/stdc++.h>
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<len;i++){
int id = word[i]-'a';
if(!nxt[now][id]){
nxt[now][id] = create();
}
now = nxt[now][id];
}
val[now]++;
}
void build(){
queue<int> 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<len;i++){
int id = word[i]-'a';
while (now&&!nxt[now][id]) now = fail[now];
if (nxt[now][id]) now = nxt[now][id];
int temp = now;
while (temp){
res+=val[temp];
//Important
val[temp]=0;
//Important
temp = fail[temp];
}
}
return res;
}
}ac;
int main(){
scanf("%d",&T);
while (T--){
ac.init();
scanf("%d",&n);
while (n--){
scanf("%s",s);
int len = strlen(s);
ac.insert(s,len);
}
ac.build();
scanf("%s",s);
int len = strlen(s);
printf("%d\n",ac.query(s,len));
}
return 0;
}
KMP
KMP+DP求最小壓縮表示法(最小迴圈節)
#include<bits/stdc++.h>
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<<dp[n]<<endl;
return 0;
}
KMP求最小迴圈節 +DP求最小壓縮表示
#include<bits/stdc++.h>
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<<dp[n]<<endl;
return 0;
}
LCA
倍增LCA:
#include<bits/stdc++.h>
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<n;i++){
int u=read(),v=read();
addEdge(u,v);addEdge(v,u);
}
}
void dfs(int node,int father){
st[node][0] = father;
dep[node] =dep[father]+1;
for (int i=1;i<=20;i++){
st[node][i] =st[st[node][i-1]][i-1];
if (!st[node][i])break;
}
for (int t =first[node];t;t=nxt[t]){
int v = des[t];
if (v==father)continue;
dfs(v,node);
}
}
int lca(int x,int y){
if (dep[x]<dep[y])swap(x,y);
for (int i=20;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<bits/stdc++.h>
#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<int> 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<n;i++){
int u,v;
scanf("%d%d",&u,&v);
E[u].push_back(v);E[v].push_back(u);
}
}
bool cmp(int x,int y){return a[x]<a[y];}
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 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<int>::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]<dep[v]){swap(u,v);}
for (int i=19;i>=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<bits/stdc++.h>
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]<a[y];}
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);
for (int i=1;i<=n;i++){
root[i] = update(root[i-1],1,n,pos[i],1);
}
}
int query_kth(int lt,int rt,int l,int r,int k){
if (l==r) return a[rk[l]];
int mid = l+r >>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<bits/stdc++.h>
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;i<n;i++){
int u,v;
scanf("%d%d",&u,&v);
addEdge(u,v);addEdge(v,u);
}
maxstatus = (1<<k)-1;
}
void getSize(int node,int father){
sz[node]=1; ssz[node]=0;
for (int t = first[node];t;t=nxt[t]){
int v = des[t];
if (v==father||vis[v])continue;
getSize(v,node);
sz[node]+=sz[v];
if (sz[v]>ssz[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<Min){
Min = val;
Minid = node;
}
for (int t = first[node];t;t=nxt[t]){
int v = des[t];
if (v==father||vis[v])continue;
find_root(v,node,root);
}
}
int getRoot(int node){
getSize(node,-1);
Min =Minid = INF;
find_root(node,-1,node);
return Minid;
}
void getStatus(int node,int father){
status[node] = status[father]|a[node];
cnt[status[node]] ++;
for (int t = first[node];t;t=nxt[t]){
int v = des[t];
if (v==father||vis[v])continue;
getStatus(v,node);
}
}
long long calc(int node,int S){
memset(cnt,0,sizeof cnt);
getStatus(node,0);
long long res =0;
for (int i=S;i;i = (i-1)&S){
if (cnt[i]){
for (int x = i;x;x=(x-1)&i){
res += cnt[i]*cnt[x^S];
}
res +=cnt[i]*cnt[0^S];
}
}
return res;
}
void solve(int node){
int root = getRoot(node);
ans+=calc(root,maxstatus);
vis[root] =true;
for (int t = first[root];t;t=nxt[t]){
int v = des[t];
if (vis[v])continue;
ans -=calc(v,maxstatus);
ans-= calc(v,a[root]^maxstatus);
solve(v);
}
}
int main(){
prework();
while (scanf("%d%d",&n,&k)!=EOF){
init(); input();
if (k==1){
cout<<1LL*n+1LL*n*(n-1)<<endl;
continue;
}
solve(1);
cout<<ans<<endl;
}
return 0;
}
求路徑長度<=K的條數 板子:
#include<stdio.h>
#include<algorithm>
#include<cstring>
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<n;i++){
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add(u,v,w); add(v,u,w);
}
}
void dfs1(int node,int father){
sum[node] = 1; dp[node] = 0;
for (int t = first[node];t;t = nxt[t]){
int v = des[t];
if (v == father||vis[v]){
continue;
}
dfs1(v,node);
sum[node] += sum[v];
dp[node] = max(dp[node],sum[v]);
}
}
void dfs2(int node,int father){
int temp = max(dp[node],Sum-sum[node]);
if (temp<Min){
Min = temp; Minid = node;
}
for (int t = first[node];t;t = nxt[t]){
int v = des[t];
if (v==father||vis[v]){ continue; }
dfs2(v,node);
}
}
int getRoot(int u){
dfs1(u,0); Sum = sum[u];
Min = INF; Minid = -1;
dfs2(u,0);
return Minid;
}
void getDist(int node,int father,int dist){
dis[num++] = dist;
for (int t = first[node];t;t = nxt[t]){
int v =des[t];
if (v == father||vis[v]){ continue; }
getDist(v,node,dist+len[t]);
}
}
int calc (int u,int val){
num=0; int res =0;
getDist(u,0,0);
sort(dis,dis+num);
int i=0;int j=num-1;
while (i<j){
if (dis[i]+dis[j]+2*val<=k){
res+=j-i;
i++;
}else{ j--; }
}
return res;
}
void solve(int u){
int root = getRoot(u);
ans +=calc(root,0); vis[root] = true;
for (int t = first[root];t;t = nxt[t]){
int v = des[t];
if (vis[v]){
continue;
}
ans-=calc(v,len[t]);
solve(v);
}
}
int main(){
while (scanf("%d%d",&n,&k)!=EOF&&n&&k){
init();
input();
solve(1);
printf("%d\n",ans);
}
return 0;
}
kd-Tree
二維樹且第三維有限制的搜尋模板:
#include<bits/stdc++.h>
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]<b.pos[cmpDem];
}
void build (int l,int r){
if (l>=r)return;
int mid = l+r >>1;
for (int i=0;i<demension;i++){
double ave =0;
for (int j=l;j<=r;j++){
ave+=hotel[j].pos[i];
}
ave/=(r-l+1);var[i] =0;
for (int j=l;j<=r;j++){
var[i]+=pow(hotel[j].pos[i]-ave,2);
}
var[i]/=(r-l+1);
}
split[mid] =-1;double maxVar=-1;
for (int i=0;i<demension;i++){
if (var[i]>maxVar){
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;i<demension;i++){
dis +=1LL*(x.pos[i]-hotel[mid].pos[i])*(x.pos[i]-hotel[mid].pos[i]);
}
if (hotel[mid].c<=x.c){
if (ansDis == dis && hotel[mid].id<hotel[ansIndex].id){
ansIndex = mid;
}else if (dis<ansDis){
ansDis = dis;
ansIndex = mid;
}
}
int d = split[mid];
LL radius = 1LL*(x.pos[d]-hotel[mid].pos[d])*(x.pos[d]-hotel[mid].pos[d]);
if (x.pos[d]<hotel[mid].pos[d]){
query(l,mid-1,x);
if (ansDis>radius){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<n;i++){
scanf("%d%d%d",&hotel[i].pos[0],&hotel[i].pos[1],&hotel[i].c);
hotel[i].id=i;
}
build (0,n-1);
}
void solve(){
Hotel x;
for (int i=1;i<=m;i++){
scanf("%d%d%d",&x.pos[0],&x.pos[1],&x.c);
ansDis = INF;ansIndex =n+1;
query(0,n-1,x);
printf("%d %d %d\n",hotel[ansIndex].pos[0],hotel[ansIndex].pos[1],hotel[ansIndex].c);
}
}
int main(){
scanf("%d",&T);
while (T--){
input();
solve();
}
return 0;
}
斜率優化DP:
裸斜率優化DP板子,方程dp[ i ] = min { dp[ j ] + ( sum[ i ]- sum[ j ] )^2 }
#include<bits/stdc++.h>
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<tail&&y(q[head+1],q[head])<=sum[i]*x(q[head+1],q[head]))
head++;
dp[i]=getdp(i,q[head])+m;
while(head+1<tail&&y(i,q[tail-1])*x(q[tail-1],q[tail-2])<=y(q[tail-1],q[tail-2])*x(i,q[tail-1]))
tail--;
q[tail++]=i;
}
printf("%I64d\n",dp[n]);
}
return 0;
}
樹上斜率DP,重點在於恢復佇列元素,方程:dp[ i ] = min{ dp[ j ] + ( sum[ i ]- sum[ j ] )^2 } +p
#include<bits/stdc++.h>
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<n-1;i++){
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
addEdge(u,v,w);addEdge(v,u,w);
}
}
void dfs(int node,int father){
vector<Node> q2;
while (l+1<r&&y(q[l],q[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<r&&y(q[r-2],q[r-1])*x(q[r-1],node)>=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<<ans<<endl;
}
int main(){
scanf("%d",&T);
while (T--){
init();
input();
solve();
}
return 0;
}
最大流
Dicnic模板
#include<bits/stdc++.h>
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<m;i++){
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
addEdge(u,v,w);addEdge(v,u,0);
}
}
bool bfs(){
memset(dep,-1,sizeof dep);
dep[ss] =0;
queue<int> 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<now;t=nxt[t]){
int v = des[t],cx = c[t];
if (dep[v]==dep[node]+1&&cx){
int x = min(cx,now-res);
x = dfs(v,x);
res +=x;
c[t] -= x;c[t^1]+=x;
}
}
if (!res) dep[node] = -2;
return res;
}
void solve(){
int res =0,del =0;
ss =1;tt =n;
while (bfs()){
while (del = dfs(ss,INF)){res +=del;}
}
cout<<res<<endl;
}
int main(){
while (scanf("%d%d",&m,&n)!=EOF){
init();
input();
solve();
}
return 0;
}
最小費用最大流
來回最短路&雙向邊&每個方向的邊只能用一次(模板)
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
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<m;i++){
int u,v,c;
scanf("%d%d%d",&u,&v,&c);
addEdge(u,v,1,c);addEdge(v,u,1,c);
}
addEdge(0,1,2,0);
}
bool spfa(){
memset(in,0,sizeof in);
memset(dis,INF,sizeof dis);
memset(pre,-1,sizeof pre);
dis[ss] =0;in[ss] =1;
queue<int> 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<<totcost<<endl;
}
int main(){
input();
solve();
return 0;
}
線段樹
區間修改,區間求和
#include<stdio.h>
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<L)return;
if (L<=l&&r<=R){
val[x]+=1LL*del*(r-l+1);
lazy[x]+=del;
return;
}
int mid = l+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<L)return 0;
if (L<=l&&r<=R)return val[x];
int mid = l+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<bits/stdc+
#define LL long long
#define inf 1<<30
#define s(a) scanf("%d",&a)
#define CL(a,b) memset(a,b,sizeof(a))
using namespace std;
const int N=5005;
int n,a,b;
float seg[N][N<<2]; // 表示X軸Y軸;
void Build_2(int l,int r,int deep,int rt) // 建y軸方向線段樹(二維);
{
seg[deep][rt]=-1.0;
if(l==r) return;
int mid=(l+r)>>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;
}
DFS靠譜找環
題目:有向圖中最多刪掉一條邊,是否可以成為DAG
#include<bits/stdc++.h>
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<int> cir;
stack<pair<int,int> > 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<m;i++){
int u,v;
scanf("%d%d",&u,&v);
addEdge(u,v);
}
}
int findcir(int node,int Eid){
if (vis[node]==2)return 0;
if (vis[node]==1){
cir.push_back(Eid);
while (stk.top().first!=node){
cir.push_back(stk.top().second);
stk.pop();
}
return 1;
}
vis[node]=1;
stk.push(make_pair(node,Eid));
for (int t = first[node];t;t=nxt[t]){if (findcir(des[t],t))return 1;}
vis[node] =2;stk.pop();
return 0;
}
int findcir2(int node,int Eid){
if (vis[node]==2)return 0;
if (vis[node]==1)return 1;
vis[node]=1;
for (int t = first[node];t;t=nxt[t]){
if (t==Eid)continue;
if (findcir2(des[t],Eid))return 1;
}
vis[node]=2;
return 0;
}
int check(int Eid){
memset(vis,0,sizeof vis);
for (int i=1;i<=n;i++)if (!vis[i])if (findcir2(i,Eid))return 0;
return 1;
}
void solve(){
memset(vis,0,sizeof vis);
for (int i=1;i<=n;i++)if (!vis[i])if (findcir(i,-1))break;
if (cir.empty()){
cout<<"YES"<<endl;
return ;
}
for (int Eid:cir){
if (check(Eid)){
cout<<"YES"<<endl;
return ;
}
}
cout<<"NO"<<endl;
}
int main(){
input();
solve();
return 0;
}
靠譜找凸包(dis注意精度,注意n=1和n=2特判)
#include<bits/stdc++.h>
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<n;i++){
scanf("%d%d",&a[i].x,&a[i].y);
rk[i]=i;
}
for (int i=1;i<n;i++){
if (a[rk[i]].y<a[rk[0]].y||a[rk[i]].y==a[rk[0]].y&&a[rk[i]].x<a[rk[0]].x)swap(rk[i],rk[0]);
}
sort(rk+1,rk+n,cmp);top=2;
st[0]=rk[0];st[1]=rk[1];
for (int i=2;i<n;i++){
while (cross(st[top-2],st[top-1],rk[i])<0)top--;
st[top++] =rk[i];
}
double ans =0;
for (int i=1;i<top;i++){ans+=dis(a[st[i]],a[st[i-1]]);}
ans+=dis(a[st[0]],a[st[top-1]]);
ans+=2*M_PI*l;
printf("%.0lf\n",ans);
}
int main(){
scanf("%d",&T);
while (T--){
solve();
if (T!=0)printf("\n");
}
return 0;
}
tarjan縮點(粗體是tarjan部分,flag是並查集)
縮點+拓撲找出度為零的最小點集
#include<bits/stdc++.h>
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<int> 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<m;i++){
int u1,u2;
scanf("%d%d",&u1,&u2);
if (t[u1]==(t[u2]+1)%h)add(u2,u1);
if (t[u2]==(t[u1]+1)%h)add(u1,u2);
}
for (int i=1;i<=n;i++){if (!dfn[i])tar(i);}
for (int i=1;i<=n;i++){
for (int t = first[i];t;t=nxt[t]){
if (flag[i]==flag[des[t]])continue;
else{d[flag[i]]++;}
}
}
cnt[0] =n+1;int ans = 0;
for (int i=1;i<=scc;i++){
if (d[i]==0&&cnt[i]<cnt[ans]){ans = i;}
}
cout<<cnt[ans]<<endl;
for (int i=1;i<=n;i++){
if (flag[i]==ans){cout<<i<<" ";}
}
cout<<endl;
return 0;
}
Tarjan邊雙連通
統計聯通分量點數和邊數
#include<bits/stdc++.h>
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 <int> 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<m;i++){
int u,v;
scanf("%d%d",&u,&v);
addEdge(u,v);addEdge(v,u);
}
}
void dfs(int u,int fa){
dfn[u] = low[u] = ++dfs_clock;
for (int t = first[u];t;t=nxt[t]){
int v = des[t];if (v==fa)continue;
if (!dfn[v]){
dfs(v,u);
low[u] = min(low[v],low[u]);
if (dfn[u]<low[v]){
isBrige[t] = true;
if (t&1){isBrige[t+1] = true;}
else{isBrige[t-1] = true;}
}
}else if (dfn[v]<dfn[u]){low[u] = min(low[u],dfn[v]);}
}
}
void blood_fill(int x){
dfn[x] = bcc_cnt;
for (int t = first[x];t;t=nxt[t]){
if (isBrige[t])continue;
int v = des[t];
if (!dfn[v]){blood_fill(v);}
}
}
void check(){
for (int i=1;i<=n;i++){cnt_n[dfn[i]]++;}
for (int i=1;i<=tot;i++){
if (isBrige[i]) continue;
cnt_e[dfn[des[i]]]++;
}
for (int i=1;i<=bcc_cnt;i++){
if (cnt_n[i]*2==cnt_e[i]){ok[i]=1;}
}
}
void output(){
for (int i=1;i<=tot;i+=2){
if (isBrige[i])continue;
if (ok[dfn[des[i]]])ans.push_back((i+1)/2);
}
sort(ans.begin(),ans.end());
cout<<ans.size()<<endl;
for (int i=0;i<ans.size();i++){printf("%d ",ans[i]);}
}
void solve(){
for (int i=1;i<=n;i++){if (!dfn[i])dfs(i,-1);}
memset(dfn,0,sizeof dfn);
for (int i=1;i<=n;i++){
if (!dfn[i]){
bcc_cnt++;
blood_fill(i);
}
}
check();output();
}
int main(){
input();
solve();
return 0;
}
Tarjan點雙連通
連通分量中點數=邊數=>整個分量為無向圖中一個獨立的簡單環。
#include<bits/stdc++.h>
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<int> ans;vector<int> 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<m;i++){
int u,v;
scanf("%d%d",&u,&v);
addEdge(u,v);addEdge(v,u);
}
}
void dfs(int u,int fa){
dfn[u] = low[u] = ++dfs_clock;
for (int t = first[u];t;t=nxt[t]){
int v = des[t];
if (v==fa)continue;
if (!dfn[v]){
st[top++] = t;dfs(v,u);
low[u] = min(low[u],low[v]);
if (low[v]>=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<temp.size();i++){
ans.push_back(temp[i]);
}
}
}
}else if (dfn[v]<dfn[u]){
st[top++] = t;
low[u] = min(low[u],dfn[v]);
}
}
}
void solve(){
for (int i=1;i<=n;i++){if (!dfn[i])dfs(i,-1);}
sort(ans.begin(),ans.end());
cout<<ans.size()<<endl;
for (int i=0;i<ans.size();i++){printf("%d ",ans[i]);}
}
int main(){
input();
solve();
return 0;
}
虛樹
給出有根帶邊權樹,每次詢問:刪除邊使得根與詢問點集不聯通,最小化邊權之和。
#include <bits/stdc++.h>
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]=