varinic的模板

这里是varinic的模板1.2


目录
字符串处理	1
1.KMP	1
2.AC自动机	4
3.后缀数组	6
4.Manacher最长回文子串	8
数据结构	10
1.主席树	10
图论	12
1.spfa	12
2.强连通	14
3.最大流	16
4.最小费用最大流	18
5.二分图匹配	20
6.KM算法	21
7.欧拉回路	23
8.LCA	25
其他	26
1.输入输出外挂	26
2.莫队算法	27

字符串处理

1.KMP
/*
pku3461(Oulipo), hdu1711(Number Sequence)
这个模板 字符串是从0开始的
Next数组是从1开始的
*/
#include <iostream>
#include <cstring>
using namespace std;

const int N = 1000002;
int next[N];
char S[N], T[N];
int slen, tlen;

void getNext()
{
    int j, k;
    j = 0; k = -1; next[0] = -1;
    while(j < tlen)
        if(k == -1 || T[j] == T[k])
            next[++j] = ++k;
        else
            k = next[k];
}
/*
返回模式串T在主串S中首次出现的位置
返回的位置是从0开始的。
*/
int KMP_Index()
{
    int i = 0, j = 0;
    getNext();

    while(i < slen && j < tlen)
    {
        if(j == -1 || S[i] == T[j])
        {
            i++; j++;
        }
        else
            j = next[j];
    }
    if(j == tlen)
        return i - tlen;
    else
        return -1;
}
/*
返回模式串在主串S中出现的次数
*/
int KMP_Count()
{
    int ans = 0;
    int i, j = 0;

    if(slen == 1 && tlen == 1)
    {
        if(S[0] == T[0])
            return 1;
        else
            return 0;
    }
    getNext();
    for(i = 0; i < slen; i++)
    {
        while(j > 0 && S[i] != T[j])
            j = next[j];
        if(S[i] == T[j])
            j++;
        if(j == tlen)
        {
            ans++;
            j = next[j];
        }
    }
    return ans;
}
int main()
{
    int TT;
    int i, cc;
    cin>>TT;
    while(TT--)
    {
        cin>>S>>T;
        slen = strlen(S);
        tlen = strlen(T);
        cout<<"模式串T在主串S中首次出现的位置是: "<<KMP_Index()<<endl;
        cout<<"模式串T在主串S中出现的次数为: "<<KMP_Count()<<endl;
    }
    return 0;
}
/*
test case
4
aaaaaa a
abcd d
aabaa b
*/

2.AC自动机

从队列里取出来的点now 在字典树上的下一个点
t=next[now][s[i]-'a']如果不存在,则t指向x=now的
失败指针对应下一个点,否者fail[t]指向x。

const int maxn=500000+10;

struct Trie{
    int next [maxn][26],fail[maxn],cnt[maxn];
    int root,L;
    int newnode(){
        fill(next[L],next[L]+26,-1);
        cnt[L++]=0;
        return L-1;
    }
    void init(){
        L=0;
        root=newnode();
    }
    void insert(char *s){
        int len=strlen(s);
        int now=root;
        for(int i=0;i<len;i++){
            if(next[now][s[i]-'a']==-1)
                next[now][s[i]-'a']=newnode();
            now=next[now][s[i]-'a'];
        }
        cnt[now]++;
    }
    void build(){
        queue<int> que;
        fail[root]=root;
        for(int i=0;i<26;i++){
            if(next[root][i]==-1)
                next[root][i]=root;
            else{
                fail[next[root][i]]=root;
                que.push(next[root][i]);
            }
        }
        while(!que.empty()){
            int now=que.front();
            que.pop();
            for(int i=0;i<26;i++){
                if(next[now][i]==-1)
                    next[now][i]=next[fail[now]][i];
                else{
                    fail[next[now][i]]=next[fail[now]][i];
                    que.push(next[now][i]);
                }
            }
        }
    }
    int query(char *s){
        int len=strlen(s);
        int now=root;
        int res=0;
        for(int i=0;i<len;i++){
            now =next[now][s[i]-'a'];
            int tmp=now;
            while(tmp!=root){
                res+=cnt[tmp];
                cnt[tmp]=0;
                tmp=fail[tmp];
            }
        }
        return res;
    }
};

Trie ac;
char s[1000000+5];

int main()
{
    int t;
    scanf("%d",&t);
    while(t--){
        ac.init();
        int n;
        scanf("%d",&n);
        for(int i=0;i<n;i++){
            scanf("%s",s);
            ac.insert(s);
        }
        ac.build();
        scanf("%s",s);
        int ans=ac.query(s);
        printf("%d\n",ans);
    }
    return 0;
}

3.后缀数组
/*
 * SPOJ 694
 * 给定一个字符串,求不相同子串个数。
 * 每个子串一定是某个后缀的前缀,那么原问题等价于求所有后缀之间的不相同子串个数。
 * 总数为n*(n-1)/2,再减掉height[i]的和就是答案
 */

#include <iostream>
#include <string.h>
#include <algorithm>
#include <stdio.h>
using namespace std;
const int MAXN=1010;

/*
*suffix array
*倍增算法  O(n*logn)
*待排序数组长度为n,放在0~n-1中,在最后面补一个0
*build_sa( ,n+1, );//注意是n+1;
*getHeight(,n);
*例如:
*n   = 8;
*num[]   = { 1, 1, 2, 1, 1, 1, 1, 2, $ };注意num最后一位为0,其他大于0
*rank[]  = { 4, 6, 8, 1, 2, 3, 5, 7, 0 };rank[0~n-1]为有效值,rank[n]必定为0无效值
*sa[]    = { 8, 3, 4, 5, 0, 6, 1, 7, 2 };sa[1~n]为有效值,sa[0]必定为n是无效值
*height[]= { 0, 0, 3, 2, 3, 1, 2, 0, 1 };height[2~n]为有效值
*
*/

int sa[MAXN];//SA数组,表示将S的n个后缀从小到大排序后把排好序的
             //的后缀的开头位置顺次放入SA中
int t1[MAXN],t2[MAXN],c[MAXN];//求SA数组需要的中间变量,不需要赋值
int rank[MAXN],height[MAXN];
//待排序的字符串放在s数组中,从s[0]到s[n-1],长度为n,且最大值小于m,
//除s[n-1]外的所有s[i]都大于0,r[n-1]=0
//函数结束以后结果放在sa数组中
void build_sa(int s[],int n,int m)
{
    int i,j,p,*x=t1,*y=t2;
    //第一轮基数排序,如果s的最大值很大,可改为快速排序
    for(i=0;i<m;i++)c[i]=0;
    for(i=0;i<n;i++)c[x[i]=s[i]]++;
    for(i=1;i<m;i++)c[i]+=c[i-1];
    for(i=n-1;i>=0;i--)sa[--c[x[i]]]=i;
    for(j=1;j<=n;j<<=1)
    {
        p=0;
        //直接利用sa数组排序第二关键字
        for(i=n-j;i<n;i++)y[p++]=i;//后面的j个数第二关键字为空的最小
        for(i=0;i<n;i++)if(sa[i]>=j)y[p++]=sa[i]-j;
        //这样数组y保存的就是按照第二关键字排序的结果
        //基数排序第一关键字
        for(i=0;i<m;i++)c[i]=0;
        for(i=0;i<n;i++)c[x[y[i]]]++;
        for(i=1;i<m;i++)c[i]+=c[i-1];
        for(i=n-1;i>=0;i--)sa[--c[x[y[i]]]]=y[i];
        //根据sa和x数组计算新的x数组
        swap(x,y);
        p=1;x[sa[0]]=0;
        for(i=1;i<n;i++)
            x[sa[i]]=y[sa[i-1]]==y[sa[i]] && y[sa[i-1]+j]==y[sa[i]+j]?p-1:p++;
        if(p>=n)break;
        m=p;//下次基数排序的最大值
    }
}
void getHeight(int s[],int n)
{
    int i,j,k=0;
    for(i=0;i<=n;i++)rank[sa[i]]=i;
    for(i=0;i<n;i++)
    {
        if(k)k--;
        j=sa[rank[i]-1];
        while(s[i+k]==s[j+k])k++;
        height[rank[i]]=k;
    }
}

char str[MAXN];
int s[MAXN];

int main()
{
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%s",str);
        int n=strlen(str);
        for(int i=0;i<=n;i++)s[i]=str[i];
        build_sa(s,n+1,128);
        getHeight(s,n);
        int ans=n*(n+1)/2;
        for(int i=2;i<=n;i++)ans-=height[i];
        printf("%d\n",ans);
    }
    return 0;
}

4.Manacher最长回文子串

#include <iostream>
#include <string.h>
#include <algorithm>
#include <stdio.h>
#include <math.h>
using namespace std;

int Proc(char pszIn[],char pszOut[])
{
    int nLen=1;
    pszOut[0]='$';
    int i=0;
    while(pszIn[i]!='\0')
    {
        pszOut[nLen++]='#';
        pszOut[nLen++]=pszIn[i];
        i++;
    }
    pszOut[nLen++]='#';
    pszOut[nLen]=0;
    return nLen;
}
void Manacher(int *p,char *str,int len)
{
    int mx=0,id=0;
    for(int i=0;i<len;i++)
    {
        p[i]=mx>i?min(p[2*id-i],mx-i):1;
        while(str[i+p[i]]==str[i-p[i]])p[i]++;
        if(i+p[i]>mx)
        {
            mx=i+p[i];
            id=i;
        }
    }
}
const int MAXN=220010;
char strIn[MAXN];
char strOut[MAXN];
int p[MAXN];
int main()
{
    while(scanf("%s",strIn)!=EOF)
    {
        int nLen=Proc(strIn,strOut);
        Manacher(p,strOut,nLen);
        int ans=1;
        for(int i=0;i<nLen;i++)
            ans=max(ans,p[i]);
        printf("%d\n",ans-1);
    }
    return 0;
}
/*
aaaa  abab
4  3
*/


数据结构

1.主席树
/*
静态区间第k大
*/
#include <iostream>  
#include <cstdio>  
#include <cstdlib>  
#include <algorithm>  
#include <cmath>  
#include <cstring>  
  
using namespace std;  
const int maxn=1e5+7;  
  
struct node{  
    int ls,rs,sum;  
}data[maxn*20];  
int cnt;  
int root[maxn];  
int a[maxn],b[maxn],mp[maxn];  
int build(int l,int r){  
    int t=cnt++;  
    data[t].sum=0;  
    if(l==r)return t;  
    int mid=l+r>>1;  
    data[t].ls=build(l,mid);  
    data[t].rs=build(mid+1,r);  
    return t;  
}  
int update(int k,int l,int r,int v){  
    int t=cnt++;  
    data[t].sum=data[k].sum+1;  
    if(l==r)return t;  
    int mid=l+r>>1;  
    if(v<=mid){  
        data[t].rs=data[k].rs;  
        data[t].ls=update(data[k].ls,l,mid,v);  
    }  
    else {  
        data[t].ls=data[k].ls;  
        data[t].rs=update(data[k].rs,mid+1,r,v);  
    }  
    return t;  
}  
int query(int t1,int t2,int l,int r,int v){  
    if(l==r)return l;  
    int mid=l+r>>1;  
    int w=data[data[t2].ls].sum-data[data[t1].ls].sum;  
    if(v<=w) return query(data[t1].ls,data[t2].ls,l,mid,v);  
    else return query(data[t1].rs,data[t2].rs,mid+1,r,v-w);  
}  
  
void debug(int t,int l,int r){  
    printf("l==%d r==%d sum==%d\n",l,r,data[t].sum);  
    if(l==r)return ;  
    int mid=l+r>>1;  
    debug(data[t].ls,l,mid);  
    debug(data[t].rs,mid+1,r);  
}  
int main()  
{  
    int n,m;  
    while(~scanf("%d%d",&n,&m)){  
        cnt=1;  
        for(int i=1;i<=n;i++){  
            scanf("%d",&a[i]);  
            b[i]=a[i];  
        }  
        sort(b+1,b+n+1);  
        int len=unique(b+1,b+1+n)-(b+1);  
        for(int i=1;i<=n;i++){  
            int t=lower_bound(b+1,b+1+len,a[i])-(b+1)+1;  
            mp[t]=a[i];a[i]=t;  
        }  
        root[0]=build(1,len);  
        for(int i=1;i<=n;i++){  
            root[i]=update(root[i-1],1,len,a[i]);  
        }  
        /*for(int i=0;i<=n;i++){ 
            printf("----i==%d------\n",i); 
            debug(root[i],1,len); 
        }*/  
        for(int i=0;i<m;i++){  
            int l,r,v;  
            scanf("%d%d%d",&l,&r,&v);if(l>r)swap(l,r);  
            printf("%d\n",mp[query(root[l-1],root[r],1,len,v)]);  
        }  
    }  
    return 0;  
}  


图论

1.spfa

#include <stdio.h>  
#include <cstring>  
#include <iostream>  
#include <algorithm>  
#include <queue>  
using namespace std;  
const int maxn=300001;  
const int inf =0x7ffffff;  
struct edge  
{  
    int from,to,w,next;  
}e[1000001];  
int head[maxn];  
int vis[maxn];  
int dist[maxn];  
int n,m,t;  
void add(int i,int j,int w)  
{  
    e[t].from=i;  
    e[t].to=j;  
    e[t].w=w;  
    e[t].next=head[i];  
    head[i]=t++;  
}  
void spfa(int s)  
{  
    queue <int> q;  
    for(int i=1;i<=n;i++)  
    dist[i]=inf;  
    memset(vis,false,sizeof(vis));  
    q.push(s);  
    dist[s]=0;  
    while(!q.empty())  
    {  
        int u=q.front();  
        q.pop();  
        vis[u]=false;  
        for(int i=head[u];i!=-1;i=e[i].next)  
        {  
            int v=e[i].to;  
            if(dist[v]>dist[u]+e[i].w)  
            {  
                dist[v]=dist[u]+e[i].w;  
                if(!vis[v])  
                {  
                    vis[v]=true;  
                    q.push(v);  
                }  
            }  
        }  
    }  
}  
int main()  
{  
    int a,b,c,s,e;  
    scanf("%d%d",&n,&m);  
    t=0;  
    memset(head,-1,sizeof(head));  
    while(m--)  
    {  
        scanf("%d%d%d",&a,&b,&c);  
        add(a,b,c);  
    }  
    scanf("%d%d",&s,&e);  
    spfa(s);  
    if(dist[e]==inf) printf("-1\n");  
    else printf("%d\n",dist[e]);  
    return 0;  
}

2.强连通
/*
E2中的点从1到Bcnt
E1中的点从0到n-1
*/
#include <bits/stdc++.h>  
  
using namespace std;  
const int maxn=1e5+4;  
int dfn[maxn], low[maxn] ,instack[maxn], belong[maxn] ;  
int stap[maxn],Stop,Bcnt,Dindex;  
int n,m,flag;  
  
struct edge{  
    int to;  
};  
vector<edge> E[maxn];  
vector<edge> E2[maxn];  
  
void tarjan(int i){  
    int j;  
    dfn[i]=low[i]=++Dindex;  
    instack[i]=1;  
    stap[++Stop]=i;  
    for( int k=0;k<E[i].size();k++ ){  
        j=E[i][k].to;  
        if( !dfn[j] ){  
            tarjan(j);  
            if( low[j]<low[i] )  
                low[i]=low[j];  
        }  
        else if( instack[j] &&dfn[j]< low[i]  )  
            low[i]=dfn[j];  
    }  
    if( dfn[i]==low[i] ){  
        Bcnt++;  
        do{  
            j=stap[Stop--];  
            instack[j]=0;  
            belong[j]=Bcnt;  
        }  
        while( j!=i );  
    }  
}  

void solve(){  
    int i;  
    Stop=Bcnt=Dindex=0;  
    memset(dfn,0,sizeof(dfn));  
    memset(instack,0,sizeof(instack));  
    memset(belong,0,sizeof(belong));  
    memset(low,0,sizeof(low));  
    for(int i=0;i<n;i++){        //代表点从0到n-1
        if(!dfn [i] ) tarjan(i);  
    }  
}  
  
void init(){  
    for(int i=0;i<=n;i++){  
        E[i].clear();  
        E2[i].clear();  
    }  
}  
  
int dfs(int now){  
    if( now==belong[n-1] ){  
        flag=1;return 0;  
    }  
    int ans=1e9;  
    for(int i=0;i< E2[now].size();i++ )ans=min( ans,dfs(E2[now][i].to)+1 );  
    return ans;  
}  
  
int main(){  
    int t;  
    cin>>t;  
    while(t--){  
        scanf("%d%d",&n,&m);  
        init();  
        for(int i=0;i<m;i++){  
            int x,y;  
            scanf("%d%d",&x,&y);  
            E[x].push_back( edge{y} );  
            //E[y].push_back( edge{x} );  
        }  
        solve();  
        for(int i=0;i<n;i++){  
            for(int j=0;j< E[i].size();j++ ){  
                if( belong[i]!=belong[ E[i][j].to ] )  
                    E2[belong[i] ].push_back( edge{ belong[ E[i][j].to ]  } );  
            }  
        }  
        flag=0;  
        int ans=dfs( belong[0] );  
        if(flag) printf("%d\n",ans);  
        else puts("-1");  
    }  
    return 0;  
}  


3.最大流

Dinic

const int maxn=1e4;
const int inf=1e9+7;
struct edge{int to,cap,rev;};
vector<edge> G[maxn];
int level[maxn];
int iter[maxn];

void add(int from,int to,int cap){
	G[from].push_back(edge{to,cap,G[to].size()});
	G[to].push_back(edge{from,0,G[from].size()-1});
}

void bfs(int s){
	memset(level,-1,sizeof(level));
	queue<int> que;
	level[s]=0;
	que.push(s);
	while(!que.empty()){
		int v=que.front();que.pop();
		for(int i=0;i<G[v].size();i++){
			edge &e=G[v][i];
			if(e.cap>0&&level[e.to]<0){
				level[e.to]=level[v]+1;
				que.push(e.to);
			}
		}
	}
}

int dfs(int v,int t,int f){
	if(v==t)return f;
	for(int &i=iter[v];i<G[v].size();i++){
		edge &e=G[v][i];
		if(e.cap>0&&level[v]<level[e.to]){
			int d=dfs(e.to,t,min(f,e.cap));
			if(d>0){
				e.cap-=d;
				G[e.to][e.rev].cap+=d;
				return d;
			}
		}
	}
	return 0;
}

int max_flow(int s,int t){
	int flow=0;
	for(;;){
		bfs(s);
		if(level[t]<0)return flow;
		memset(iter,0,sizeof(iter));
		int f;
		while((f=dfs(s,t,inf))>0){
			flow+=f;
		}
	}
}

4.最小费用最大流

#include <cstdio>  
#include <cstring>  
#include <queue>  
#include <stack>  
#include <vector>  
#include <cmath>  
#include <cstdlib>  
#include <algorithm>  
#define MAXN 200+10  
#define MAXM 80000+100  
#define INF 0x3f3f3f3f  
using namespace std;  
struct Edge  
{  
    int from, to, cap, flow, cost, next;  
};  
Edge edge[MAXM];  
int head[MAXN], edgenum;  
int pre[MAXN];//记录增广路径上 到达点i的边的编号  
int dist[MAXN];  
bool vis[MAXN];  
int N, M;//点数 边数  
int source, sink;//超级源点 超级汇点  
void init()  
{  
    edgenum = 0;  
    memset(head, -1, sizeof(head));  
}  
void addEdge(int u, int v, int w, int c)  
{  
    Edge E1 = {u, v, w, 0, c, head[u]};  
    edge[edgenum] = E1;  
    head[u] = edgenum++;  
    Edge E2 = {v, u, 0, 0, -c, head[v]};  
    edge[edgenum] = E2;  
    head[v] = edgenum++;  
}  
bool SPFA(int s, int t)//寻找花销最少的路径  
{  
    //跑一遍SPFA 找s——t的最少花销路径 且该路径上每一条边不能满流  
    //若存在 说明可以继续增广,反之不能  
    queue<int> Q;  
    memset(dist, INF, sizeof(dist));  
    memset(vis, false, sizeof(vis));  
    memset(pre, -1, sizeof(pre));  
    dist[s] = 0;  
    vis[s] = true;  
    Q.push(s);  
    while(!Q.empty())  
    {  
        int u = Q.front();  
        Q.pop();  
        vis[u] = false;  
        for(int i = head[u]; i != -1; i = edge[i].next)  
        {  
            Edge E = edge[i];  
            if(dist[E.to] > dist[u] + E.cost && E.cap > E.flow)//可以松弛 且 没有满流  
            {  
                dist[E.to] = dist[u] + E.cost;  
                pre[E.to] = i;//记录前驱边 的编号  
                if(!vis[E.to])  
                {  
                    vis[E.to] = true;  
                    Q.push(E.to);  
                }  
            }  
        }  
    }  
    return pre[t] != -1;//可达返回true  
}  
void MCMF(int s, int t, int &cost, int &flow)  
{  
    flow = 0;//总流量  
    cost = 0;//总费用  
    while(SPFA(s, t))//每次寻找花销最小的路径  
    {  
        int Min = INF;  
        //通过反向弧 在源点到汇点的最少花费路径 找最小增广流  
        for(int i = pre[t]; i != -1; i = pre[edge[i^1].to])  
        {  
            Edge E = edge[i];  
            Min = min(Min, E.cap - E.flow);  
        }  
        //增广  
        for(int i = pre[t]; i != -1; i = pre[edge[i^1].to])  
        {  
            edge[i].flow += Min;  
            edge[i^1].flow -= Min;  
            cost += edge[i].cost * Min;//增广流的花销  
        }  
        flow += Min;//总流量累加  
    }  
}  
int main()  
{  
    while(scanf("%d%d", &N, &M), N||M)  
    {  
        init();  
        getMap();//建图   
        int cost, flow;//最小费用 最大流  
        MCMF(source, sink, cost, flow);  
        printf("%d %d\n", cost, flow);//最小费用 最大流  
    }  
    return 0;  
}  

5.二分图匹配

int V;
vector<int> G[maxn];
int match[maxn];
bool used[maxn];

void add(int u,int v){
    G[u].push_back(v);
    G[v].push_back(u);
}

bool dfs(int v){
    used[v]=true;
    for(int i=0;i<G[v].size();i++){
        int u=G[u][i],w=match[u];
        if(w<0||!used[w]&&dfs(w)){
            match[v]=u;
            natch[u]=v;
            return true;
        }
    }
    return false;
}

int hungary(){
    int res=0;
    memset(match,-1,sizeof(match));
    for(int v=0;v<V;v++){
        if(match[v]<0){
            memset(used,0,sizeof(used));
            if(dfs(v))res++;
        }
    }
    return res;
}


6.KM算法

#include <stdio.h>
#include <algorithm>
#include <string.h>
#include <iostream>
using namespace std;

/*  KM算法
 *   复杂度O(nx*nx*ny)
 *  求最大权匹配
 *   若求最小权匹配,可将权值取相反数,结果取相反数
 *  点的编号从0开始
 */
const int N = 310;
const int INF = 0x3f3f3f3f;
int nx,ny;//两边的点数
int g[N][N];//二分图描述
int linker[N],lx[N],ly[N];//y中各点匹配状态,x,y中的点标号
int slack[N];
bool visx[N],visy[N];

bool DFS(int x)
{
    visx[x] = true;
    for(int y = 0; y < ny; y++)
    {
        if(visy[y])continue;
        int tmp = lx[x] + ly[y] - g[x][y];
        if(tmp == 0)
        {
            visy[y] = true;
            if(linker[y] == -1 || DFS(linker[y]))
            {
                linker[y] = x;
                return true;
            }
        }
        else if(slack[y] > tmp)
            slack[y] = tmp;
    }
    return false;
}
int KM()
{
    memset(linker,-1,sizeof(linker));
    memset(ly,0,sizeof(ly));
    for(int i = 0;i < nx;i++)
    {
        lx[i] = -INF;
        for(int j = 0;j < ny;j++)
            if(g[i][j] > lx[i])
                lx[i] = g[i][j];
    }
    for(int x = 0;x < nx;x++)
    {
        for(int i = 0;i < ny;i++)
            slack[i] = INF;
        while(true)
        {
            memset(visx,false,sizeof(visx));
            memset(visy,false,sizeof(visy));
            if(DFS(x))break;
            int d = INF;
            for(int i = 0;i < ny;i++)
                if(!visy[i] && d > slack[i])
                    d = slack[i];
            for(int i = 0;i < nx;i++)
                if(visx[i])
                    lx[i] -= d;
            for(int i = 0;i < ny;i++)
            {
                if(visy[i])ly[i] += d;
                else slack[i] -= d;
            }
        }
    }
    int res = 0;
    for(int i = 0;i < ny;i++)
        if(linker[i] != -1)
            res += g[linker[i]][i];
    return res;
}
//HDU 2255
int main()
{
    int n;
    while(scanf("%d",&n) == 1)
    {
        for(int i = 0;i < n;i++)
            for(int j = 0;j < n;j++)
                scanf("%d",&g[i][j]);
        nx = ny = n;
        printf("%d\n",KM());
    }
    return 0;
}

7.欧拉回路

#include<iostream>  
#include<stack>  
const int MAXN=111;  
using namespace std;  
  
stack<int>S;  
int edge[MAXN][MAXN];  
int n,m;  
  
void dfs(int x){  
    S.push(x);  
    for(int i=1;i<=n;i++){  
        if(edge[x][i]>0){  
            edge[i][x]=edge[x][i]=0;//删除此边  
            dfs(i);  
            break;  
        }  
    }  
}  
  
//Fleury算法的实现  
void Fleury(int x){  
    S.push(x);  
    while(!S.empty()){  
        int b=0;  
        for(int i=1;i<=n;i++){  
            if(edge[S.top()][i]>0){  
                b=1;  
                break;  
            }  
        }  
        if(b==0){  
            printf("%d",S.top());  
            S.pop();  
        }else {  
            int y=S.top();  
            S.pop();  
            dfs(y);//如果有,就dfs  
        }  
    }  
    printf("\n");  
}  
  
int main(){  
    scanf("%d%d",&n,&m); //读入顶点数以及边数  
    memset(edge,0,sizeof(edge));  
    int x,y;  
    for(int i=1;i<=m;i++){  
        scanf("%d%d",&x,&y);  
        edge[x][y]=edge[y][x]=1;  
    }  
    //如果存在奇数顶点,则从奇数顶点出发,否则从顶点0出发  
    int num=0,start=1;  
    for(int i=1;i<=n;i++){                        //判断是否存在欧拉回路  
        int degree=0;  
        for(int j=1;j<=n;j++){  
            degree+=edge[i][j];  
        }  
        if(degree&1){  
            start=i,num++;  
        }  
    }  
    if(num==0||num==2){  
        Fleury(start);  
    }else  
        printf("No Euler Path\n");  
    return 0;  
}  

8.LCA

vector<int> G[maxn];
int root;
int parent[40][maxn];
int depth[maxn];

void dfs(int v,int p,int d){
    parent[0][v]=p;
    depth[v]=d;
    for(int i=0;i<G[v].size();i++){
        if(G[v][i]!=p)dfs(G[v][i],v,d+1);
    }
}

void init(int V){
    dfs(root,-1,0);
    for(int k=0;k+1<maxn;k++){
        for(int v=0;v<V;v++){
            if(parent[k][v]<0)parent[k+1][v]=-1;
            else parent[k+1][v]=parent[k][parent[k][v]];
        }
    }
}

int lca(int u,int v){
    if(depth[u]>depth[v])swap(u,v);
    for(int k=0;k<maxn;k++){
        if((depth[v]-depth[u])>>k&1){
            v=parent[k][v];
        }
    }
    if(u==v)return u;
    for(int k=maxn-1;k>=0;k--){
        if(parent[k][u]!=parent[k][v]){
            u=parent[k][u];
            v=parent[k][v];
        }
    }
    return parent[0][u];
}


其他

1.输入输出外挂
inline void read(int &z)  {
    bool sig = false;
    char ch = getchar();
    while (ch<'0' || ch>'9') {ch=='-'?sig=true:false;ch = getchar();}
    int x = ch - '0';
    while ((ch = getchar()) >= '0'&&ch <= '9') x = x * 10 + ch - '0';
    z = sig ? -x : x;
}

inline void out(int x){
    if ( x > 9 ) out ( x / 10 );
    putchar ( x % 10 + '0');
}


2.莫队算法
#include<iostream>  
#include<cstdio>  
#include<cstdlib>  
#include<vector>  
#include<cmath>  
#include<string>  
#include<algorithm>  
#include<set>  
#include<map>  
#include<cstring>  
#include<queue>  
#include<stack>  
#include<list>  
  
using namespace std;  
  
typedef long long ll;  
const int MAXN=50010;  
  
struct Query{  
    int L,R,id;  
}node[MAXN];  
  
ll gcd(ll a,ll b){  
    if(b==0)return a;  
    return gcd(b,a%b);  
}  
  
struct Ans{  
    ll a,b;  
    void reduce(){  
        ll d=gcd(a,b);  
        a/=d;b/=d;  
    }  
}ans[MAXN];  
  
int a[MAXN];  
int num[MAXN];  
int n,m,unite;  
  
bool cmp( Query a,Query b ){  
    if(a.L/unite==b.L/unite)return a.R<b.R;  
    return a.L/unite<b.L/unite;  
}  
  
ll pow2(ll x){  
    return x*x;  
}  
  
void work(){  
    ll tmp=0;  
    memset(num,0,sizeof(num));  
    int L=1;  
    int R=0;  
    for(int i=0;i<m;i++){  
        while( R<node[i].R ){  
            R++;  
            tmp-= pow2( num[a[R]] );  
            num[ a[R] ]++;  
            tmp+= pow2( num[a[R]] );  
        }  
        while( R>node[i].R ){  
            tmp-= pow2( num[a[R]] );  
            num[ a[R] ]--;  
            tmp+= pow2( num[a[R]] );  
            R--;  
        }  
        while( L<node[i].L ){  
            tmp-= pow2( num[a[L]] );  
            num[ a[L] ]--;  
            tmp+= pow2( num[a[L]] );  
            L++;  
        }  
        while( L>node[i].L ){  
            L--;  
            tmp-= pow2( num[a[L]] );  
            num[ a[L] ]++;  
            tmp+= pow2( num[a[L]] );  
        }  
        ans[ node[i].id ].a=tmp-(R-L+1);  
        ans[ node[i].id ].b=(ll) (R-L+1)*(R-L);  
        ans[ node[i].id ].reduce();  
    }  
}  
  
int main()  
{  
    while(scanf("%d%d",&n,&m)!=EOF){  
        for(int i=1;i<=n;i++){  
            scanf("%d",&a[i]);  
        }  
        for(int i=0;i<m;i++){  
            node[i].id=i;  
            scanf("%d%d",&node[i].L,&node[i].R);  
        }  
        unite=(int ) sqrt(n);  
        sort( node,node+m,cmp );  
        work();  
        for(int i=0;i<m;i++){  
            printf("%lld/%lld\n",ans[i].a,ans[i].b);  
        }  
    }  
    return 0;  
}  





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值