这里是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;
}