ACM模板(个人代码集整理)(博客停止更新,内附github链接,会在github继续更新)

为方便区域赛打印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;  
    }  

 

DFS靠谱找环

 

题目:有向图中最多删掉一条边,是否可以成为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

tarjan缩点(粗体是tarjan部分,flag是并查集)

缩点+拓扑找出度为零的最小点集
 

#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

Tarjan边双连通

统计联通分量点数和边数

#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

Tarjan点双连通

连通分量中点数=边数=>整个分量为无向图中一个独立的简单环。

#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<

 

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(ACM模板(个人代码集整理)(博客停止更新,内附github链接,会在github继续更新))