您的位置:首页 > 编程语言

ACM模板(个人代码集整理)(持续更新)

2017-09-27 15:06 453 查看
目录:
SAM

SA
PAM

树链剖分
01Trie

ACAM
KMP
LCA
主席树
点分治
kd-Tree
斜率优化DP

最大流Dicnic
最小费用最大流(SPFA)

线段树
dfs靠谱找环

靠谱找凸包

tarjan缩点


SAM

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
,c
[2],val
,tag
,q
;
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
,fa
,ch
[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 = +
4000
+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){
// cout<<now<<' '<<sum<<endl;
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;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++){
// printf("%d %d\n",i,k);
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;
// cout<<"1: "<<res<<endl;
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));
// cout<<i<<" "<<res<<endl;
if (lc[SA[i]]>cnt){
cnt = lc[SA[i]];
}
}
// cout<<res/2<<endl;
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
;
int tot=0,head
;
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));

14ae3
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;
//          cout<<t<<" "<<nxt[y][!t]<<endl;
if (nxt[y][!t]){
y =nxt[y][!t];
res+=bas[i];
}else{
y = nxt[y][t];
}
}
//      cout<<"Query: "<<l[y]<<" "<<id<<" "<<x<<" "<<res<<" "<<ansv<<endl;
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]);
}
// cout<<"finish"<<endl;
}
int main(){
scanf("%s",s+1);
n = strlen(s+1);
for (int i=1;i<=n;i++){
dp[i]=INF;
}
// cout<<n<<endl;
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
<<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]);
}
// cout<<"finish"<<endl;
}
int main(){
scanf("%s",s+1);
n = strlen(s+1);
for (int i=1;i<=n;i++){
dp[i]=INF;
}
// cout<<n<<endl;
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
<<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);
// printf("x=%d y=%d anc =%d ",x,y,anc);
int tmp=query_kth(root[x],root[y],root[anc],root[st[anc][0]],1,n,k);
// cout<<tmp<<endl;
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 <iostream>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <cstring>

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
);
}
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;
}
/*
3
6  10
1  2  4
2  3  5
1  4  3
4  5  3
5  6  3
6  30
1  2  4
2  3  5
1  4  3
4  5  3
5  6  3
6  50
1  2  4
2  3  5
1  4  3
4  5  3
5  6  3
*/

最大流

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;
}
/*
4 5
1 2 1
2 3 1
3 4 1
1 3 2
2 4 2
*/

线段树

区间修改,区间求和

#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<iostream>
#include<string>
#include<cstdio>
#include<cstring>
#include<queue>
#include<map>
#include<cmath>
#include<stack>
#include<set>
#include<vector>
#include<algorithm>
#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<<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) swap(h1,h2); // swap函数的使用丢失精度很严重,得用float才能AC;
//if(x1>x2) swap(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;
    
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  ACM模板