矩阵快速幂
斐波那契数列
简单的快速求斐波那契数列某一项
#include <iostream>
#define N 2 //a[N][N]
using namespace std;
int MOD; //avoid being too big
struct matrix{
long long a[N][N];
matrix(){
for(int i=0;i<N;i++)
for(int j=0;j<N;j++)
a[i][j]=0;
}
matrix operator * (const matrix &y){
matrix z;
for(int i=0;i<N;i++){
for(int j=0;j<N;j++){
for(int k=0;k<N;k++)
z.a[i][j]+=a[i][k]*y.a[k][j]%MOD;
z.a[i][j]%=MOD;
}
}
return z;
}
};
matrix mat_pow(matrix res, int n){
/** matrix multiply, only for N==2
c=(1 1)
(1 0)
res=(f(2) 0 )
( 0 f(1))
return: res (res.a[0][0]+res.a[0][1]==the number of Fab[n])
**/
/*int return
if(n==1) return (res.a[1][0]+res.a[1][1])%MOD;
if(n==2) return (res.a[0][0]+res.a[0][1])%MOD;
*/
/*matrix return*/
if(n<=2) return res;
n-=2;
matrix c;
c.a[0][0]=c.a[0][1]=c.a[1][0]=1;c.a[1][1]=0;
while(n){
if(n&1) res=res*c;
c=c*c;
n/=2;
}
//int: return (res.a[0][0]+res.a[0][1])%MOD;
return res;
}
int quick_pow(int x, int y, int n) {
if(n==0)return x%MOD;
if(n==1)return y%MOD;
matrix ans,tmp;
tmp.a[0][0]=1;
ans.a[0][0]=(x+y)%MOD;
for (int i=0;i<N;++i) {
tmp.a[i][1-i]=1;
ans.a[i][1-i]=y%MOD;
}
n-=2;
while(n){
if(n&1)ans=ans*tmp;
n/=2;
tmp=tmp*tmp;
}
return ans.a[0][0];
}
int main(){
int T;
scanf("%d",&T);
for(int i=1;i<=T;i++){
int a,b,n,m;
scanf("%d%d%d%d",&a,&b,&n,&m);
MOD=1;while(m--) MOD*=10;
matrix res;
res.a[0][0]=a+b;res.a[1][1]=b;
matrix t=mat_pow(res,n);
int fab;
if(n==1) fab=(t.a[1][0]+t.a[1][1])%MOD;
else fab=(t.a[0][0]+t.a[0][1])%MOD;
printf("%d\n",fab);
}
return 0;
}
并查集
简单的并查集
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <vector>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <list>
#define Swap(a,b) {a=a^b;b=b^a;a=a^b;}
using namespace std;
int n,m;
int parent[50005];
int root(int x){
int r=x,tmp;
while(r!=parent[r]) r=parent[r];
while(x!=r){
tmp=parent[x];parent[x]=r;x=tmp;
}
return x;
}
//int find(int x){return x==fi[x]?x:fi[x]=find(fi[x]);}
void Union(int a,int b){
int ap=root(a),bp=root(b);
if(ap==bp) return;
if(ap<bp){
parent[bp]=ap;
}else{
parent[ap]=bp;
}
}
int main(){
int kase=0;
while(scanf("%d%d",&n,&m)!=EOF&&(n!=0||m!=0)){
for(int i=0;i<=n;i++){
parent[i]=i;
}
while(m--){
int k,one,oth;
scanf("%d%d",&k,&one);
//while()
scanf("%d",&oth);
Union(one,oth);
}
printf("Case %d: %d\n",++kase,m);
}
return 0;
}
树
前中后序输入
给予前序和中序 或 后序和中序 建树:
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <vector>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <list>
#define Swap(a,b) {a=a^b;b=b^a;a=a^b;}
#define max(a,b) (a>b?a:b)
#define INF 0x3f3f3f3f
using namespace std;
int preorder[100005],inorder[100005],postorder[100005];
typedef struct node{
int val;
node *left,*right;
node(int x){
val=x;left=right=NULL;
}
}node;
map<int,node*>getNode; //get &node by int from tree
map<int,int>pos; //get position by int from inorder
node *builtByPreIn(node *root,int prel,int prer,int inl,int inr){
root=new node(preorder[prel]);
getNode[preorder[prel]]=root; //register current node
int i;
i=pos[preorder[prel]]; //find root's value correspond position in inorder
//for(i=inl;i<=inr;i++) if(inorder[i]==preorder[prel]) break;
if(i!=inl){//has left child
root->left=builtByPreIn(root->left,prel+1,prel+i-inl,inl,i-1); //i-inl: left children's number
}
if(i!=inr){//has right child
root->right=builtByPreIn(root->right,prel+i-inl+1,prer,i+1,inr);
}
return root;
}
node *builtByPostIn(node *root,int postl,int postr,int inl,int inr){
root=new node(postorder[postr]);
getNode[postorder[postr]]=root; //register current node
int i;
i=pos[postorder[postr]]; //find root's value correspond position in inorder
//for(i=inl;i<=inr;i++) if(inorder[i]==postorder[postr]) break;
if(i!=inl){//has left child
root->left=builtByPostIn(root->left,postl,postl+i-inl-1,inl,i-1); //inr-i: right children's number
}
if(i!=inr){//has right child
root->right=builtByPostIn(root->right,postr-(inr-i),postr-1,i+1,inr);
}
return root;
}
void preorderTraverse(node *cur){
if(cur) cout<<cur->val<<' ';
if(cur->left)preorderTraverse(cur->left);
if(cur->right)preorderTraverse(cur->right);
}
void inorderTraverse(node *cur){
if(cur->left)inorderTraverse(cur->left);
if(cur) cout<<cur->val<<' ';
if(cur->right)inorderTraverse(cur->right);
}
void postorderTraverse(node *cur){
if(cur->left)postorderTraverse(cur->left);
if(cur->right)postorderTraverse(cur->right);
if(cur) cout<<cur->val<<' ';
}
int main(){
/* pre & in & post
8
5 3 7 2 6 4 8 1
7 2 3 4 6 5 1 8
2 7 4 6 3 1 8 5
*/
int n; //n: node numbers
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&preorder[i]); //input preorder
for(int i=1;i<=n;i++){ //input inorder
scanf("%d",&inorder[i]);
pos[inorder[i]]=i;
}
for(int i=1;i<=n;i++) scanf("%d",&postorder[i]); //input postorder
node *tree=NULL;
tree=builtByPostIn(tree,1,n,1,n);
cout<<"pre order: ";preorderTraverse(tree);cout<<endl;
cout<<"in order: ";inorderTraverse(tree);cout<<endl;
cout<<"post order: ";postorderTraverse(tree);cout<<endl;
return 0;
}
带乘法线段树
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <vector>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <list>
#define Swap(a,b) {a=a^b;b=b^a;a=a^b;}
#define INF 0x3f3f3f3f
#define INFll 0x3f3f3f3f3f3f3f3fll
using namespace std;
long long MOD;int n;
struct node{
int ll,rr;
long long val,mul,add;
node(){
ll=rr=0;val=0ll;mul=1ll;add=0ll;
}
}tree[400005];
void build(int curpos,int l,int r){
tree[curpos].ll=l;tree[curpos].rr=r;
if(l==r){
scanf("%lld",&tree[curpos].val);
return;
}
int m=(l+r)/2;
build(curpos*2,l,m);
build(curpos*2+1,m+1,r);
tree[curpos].val=(tree[curpos*2].val+tree[curpos*2+1].val)%MOD;
}
void down(int curpos){
tree[curpos*2].val=(tree[curpos*2].val*tree[curpos].mul+tree[curpos].add*(tree[curpos*2].rr-tree[curpos*2].ll+1))%MOD;
tree[curpos*2+1].val=(tree[curpos*2+1].val*tree[curpos].mul+tree[curpos].add*(tree[curpos*2+1].rr-tree[curpos*2+1].ll+1))%MOD;
tree[curpos*2].mul=(tree[curpos*2].mul*tree[curpos].mul)%MOD;
tree[curpos*2+1].mul=(tree[curpos*2+1].mul*tree[curpos].mul)%MOD;
tree[curpos*2].add=(tree[curpos*2].add*tree[curpos].mul+tree[curpos].add)%MOD;
tree[curpos*2+1].add=(tree[curpos*2+1].add*tree[curpos].mul+tree[curpos].add)%MOD;
tree[curpos].mul=1ll;
tree[curpos].add=0ll;
}
int _left,_right,delta;
long long ans;
void add_range(int curpos){
if(tree[curpos].ll>=_left&&tree[curpos].rr<=_right){
tree[curpos].val=(tree[curpos].val+(tree[curpos].rr-tree[curpos].ll+1)*delta)%MOD;
tree[curpos].add=(tree[curpos].add+delta)%MOD;
return;
}
down(curpos);
int m=(tree[curpos].ll+tree[curpos].rr)/2;
if(_left<=m) add_range(curpos*2);
if(_right>m) add_range(curpos*2+1);
tree[curpos].val=(tree[curpos*2].val+tree[curpos*2+1].val)%MOD;
}
void mul_range(int curpos){
if(_left<=tree[curpos].ll&&tree[curpos].rr<=_right){
tree[curpos].val=(tree[curpos].val*delta)%MOD;
tree[curpos].mul=(tree[curpos].mul*delta)%MOD;
tree[curpos].add=(tree[curpos].add*delta)%MOD;
return;
}
down(curpos);
int m=(tree[curpos].ll+tree[curpos].rr)/2;
if(_left<=m) mul_range(curpos*2);
if(_right>m) mul_range(curpos*2+1);
tree[curpos].val=(tree[curpos*2].val+tree[curpos*2+1].val)%MOD;
}
void ask_range(int curpos){
if(_left<=tree[curpos].ll&&tree[curpos].rr<=_right){
ans=(tree[curpos].val+ans)%MOD;
return;
}
down(curpos);
int m=(tree[curpos].ll+tree[curpos].rr)/2;
if(_left<=m) ask_range(curpos*2);
if(_right>m) ask_range(curpos*2+1);
}
int main(){
int m;
scanf("%d%d%lld",&n,&m,&MOD);
build(1,1,n);
//cout<<"---------"<<endl;
//_left=1;_right=2;ask_range(1);
//cout<<ans<<endl;
while(m--){
int opt;
scanf("%d%d%d",&opt,&_left,&_right);
if(opt==1){
scanf("%d",&delta);
mul_range(1);
}else if(opt==2){
scanf("%d",&delta);
add_range(1);
}else if(opt==3){
ans=0ll;
ask_range(1);
printf("%lld\n",(ans+MOD)%MOD);
}
}
return 0;
}
笛卡尔树
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <vector>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <list>
#define Swap(a,b) {a=a^b;b=b^a;a=a^b;}
using namespace std;
const int N = 4000004 , INF = 0x3f3f3f3f;
int root;
struct node
{
int val , pri , fat , id , son[2];// val遵守二叉搜索树规则,pri遵守堆的规则
friend bool operator < (node a , node b)
{
return a.val < b.val;
}
void init(int val_ , int pri_ , int fat_ , int id_)
{
val = val_ , pri = pri_ , fat = fat_ , id = id_;
son[0] = son[1] = 0;
}
}tr[N];
int stk[N] , top;
int ans_fat[N] , ans_l[N] , ans_r[N];
int car_build(int n)
{
top = 0;
for(int i = 1 ; i <= n ; i++)
{
int k = top;//k是在栈上移动的指针
while(k > 0 && tr[stk[k-1]].pri > tr[i].pri) k--; // 寻找第一个小于当前元素的节点x
if(k != 0)//如果栈中还有元素
{
tr[i].fat = stk[k-1]; //当前点的father变为x
tr[stk[k-1]].son[1] = i;//当前节点插入成为x的右子节点
}
if(k != top)/*如果有element曾经出栈,那么需要将出栈的最后一个变成当前点的左
子节点,因为出栈的所有element是一条链,只需要将最小的那个元素重新连接
到树上就把整条链都连接上了*/
{
tr[stk[k]].fat = i; //出栈的最后一个的father变成当前节点
tr[i].son[0] = stk[k];//当前节点的左节点变成最后一个出栈的节点
}
stk[k++] = i; // 右链的长度也因为当前点的插入而变成(当前点插入位置的深度+1)
top = k;
}
return stk[0];//插入结束时右链的栈底的元素就是根
}
int main()
{
int n=4000000;
{
int a , b;
tr[0].init(0,0,0,0);
for(int i = 1 ; i <= n ; i++)
{
a=rand();b=rand();
//scanf("%d%d",&a,&b);
tr[i].init(a,b,0,i);
}
sort(tr + 1, tr + 1 + n);
root = car_build(n);
}
return 0;
}
LCA
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <cmath>
#include <complex>
#include <algorithm>
#include <cstring>
#include <vector>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <list>
#define Swap(a,b) {a=a^b;b=b^a;a=a^b;}
#define INF 0x3f3f3f3f
#define INFll 0x3f3f3f3f3f3f3f3fll
using namespace std;
class Graph{
public:
vector<vector<int> >edge;
int vertices;
private:
struct ques{
int snum,lca,tar;
ques(){
snum=0;lca=0;tar=0;
}
ques(int _num,int _tar):snum(_num),tar(_tar){}
};
vector<int>parent;
vector<int>vis;
vector<list<ques> >query;
vector<int>ans;
public:
Graph(){
edge.clear();parent.clear();vis.clear();query.clear();ans.clear();vertices=0;
}
Graph(int n):vertices(n){
edge.clear();parent.clear();vis.clear();query.clear();ans.clear();vertices=n;
edge.resize(n+1);
}
void resize(int n){
vertices=n;edge.clear();edge.resize(n+1);
}
void build(){
/** you need to edit it
input:
edge[][]
*/
for(int i=0;i<vertices-1;++i){
int a,b;
scanf("%d%d",&a,&b);
edge[a].push_back(b);
edge[b].push_back(a);
}
}
private:
int root(int x){
int ans=x,tmp;
while(parent[ans]!=ans) ans=parent[ans];
while(x!=ans){
tmp=x;
x=parent[x];
parent[tmp]=ans;
}
return ans;
}
void Tarjan_dfs(int curpos,int fa){
int aim;
for(int i=0;i<(int)edge[curpos].size();++i){
aim=edge[curpos][i];
if(aim==fa) continue;
Tarjan_dfs(aim,curpos);
parent[aim]=curpos;
vis[aim]=1;
}
for(list<ques>::iterator it=query[curpos].begin();it!=query[curpos].end();++it){
aim=it->tar;
if(vis[aim]){
ans[it->snum]=root(aim);
}
}
query[curpos].clear();
}
public:
void Tarjan(int query_num,int rt=1){
parent.resize(vertices+1); for(int i=0;i<=vertices;++i) parent[i]=i;
vis.resize(vertices+1,0);
query.clear();query.resize(vertices+1);
ans.resize(query_num);
for(int i=0;i<query_num;++i){
int a,b;
scanf("%d%d",&a,&b);
if(a==b){
ans[i]=a;
}else{
query[a].push_back(ques(i,b));
query[b].push_back(ques(i,a));
}
}
Tarjan_dfs(rt,0);
}
void showAns(){
//you need to edit it
for(int i=0;i<(int)ans.size();++i) printf("%d\n",ans[i]);
}
};
int main(){
int n,m,rot;
scanf("%d%d%d",&n,&m,&rot);
Graph g(n);
g.build();
g.Tarjan(m,rot);
g.showAns();
return 0;
}
树状数组
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <vector>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <list>
#define INF 0x3f3f3f3f
#define INFll 0x3f3f3f3f3f3f3f3fll
using namespace std;
template <typename _type_>
struct TreeArray1{ //单点修改、区间查询
_type_ *_BinIndexTree; //Binaray Indexed Tree 树状数组
int _n; //长度 1~n
TreeArray1(){
_BinIndexTree=NULL;_n=0;
}
TreeArray1(int n){
_n=n;
_BinIndexTree=(_type_ *)calloc(2*_n,sizeof(_type_));
}
TreeArray1(_type_ *arr,int n){
_n=n;
_BinIndexTree=(_type_ *)calloc(2*_n,sizeof(_type_));
for(int i=1;i<=n;++i){
add(i,arr[i]);
}
}
/*
int lowbit(int x){
//x'father=x+lowbit(x)
//x'child=x-lowbit(x)
return x&(-x);
}*/
void build(int n){ //正常数组 单点修改、区间查询
_n=n;
_BinIndexTree=new _type_[2*n];
memset(_BinIndexTree,0,sizeof(_BinIndexTree));
long long tmp;
for(int i=1;i<=n;++i){
scanf("%lld",&tmp);
add(i,(_type_)tmp);
}
}
void add(int pos,_type_ x){ //tree[pos]+=x 单点修改
while(pos<=_n){
_BinIndexTree[pos]+=x;
pos+=(pos&-pos);
}
}
private: _type_ sum(int pos){ //sum[1~pos] 区间查询
_type_ res=0;
while(pos){
res+=_BinIndexTree[pos];
pos-=(pos&-pos);
}
return res;
}
public: _type_ sum(int left,int right){ //sum[left~right] 区间查询
return sum(right)-sum(left-1);
}
void show(){
for(int i=1;i<=_n;++i){
printf("%d ",_BinIndexTree[i]);
}
}
};
template <typename _type_>
struct TreeArray2{ //区间修改、单点查询
_type_ *_BinIndexTree; //Binaray Indexed Tree 树状数组
int _n; //长度 1~n
TreeArray2(){
_BinIndexTree=NULL;_n=0;
}
TreeArray2(int n){
_n=n;
_BinIndexTree=(_type_ *)calloc(2*_n,sizeof(_type_));
}
TreeArray2(_type_ *arr,int n){
_n=n;
_BinIndexTree=(_type_ *)calloc(2*_n,sizeof(_type_));
for(int i=1;i<=n;++i){
add(i,arr[i]);
}
}
void build(int n){ //差分数组 区间修改、单点查询
_n=n;
_BinIndexTree=new _type_[2*n];
memset(_BinIndexTree,0,sizeof(_BinIndexTree));
long long pre=0,tmp;
for(int i=1;i<=n;++i){
scanf("%lld",&tmp);
add(i,(_type_)tmp-pre);
pre=tmp;
}
}
private: void add(int pos,_type_ x){ //tree[pos]+=x
while(pos<=_n){
_BinIndexTree[pos]+=x;
pos+=(pos&-pos);
}
}
public: void add(int left,int right,_type_ x){ //tree[left~right]+=x 区间修改
return add(left,x),add(right+1,-x);
}
_type_ sum(int pos){ //sum[1~pos] 单点查询
_type_ res=0;
while(pos){
res+=_BinIndexTree[pos];
pos-=(pos&-pos);
}
return res;
}
_type_ operator [](int pos){ //单点查询
return sum(pos);
}
void show(){
for(int i=1;i<=_n;++i){
printf("%d ",_BinIndexTree[i]);
}
}
};
template <typename _type_>
struct TreeArray{ //区间修改、区间查询
_type_ *_BinIndexTree1;
_type_ *_BinIndexTree2;
int _n; //长度 1~n
TreeArray(){
_BinIndexTree1=_BinIndexTree2=NULL;_n=0;
}
TreeArray(int n){
_n=n;
_BinIndexTree1=(_type_ *)calloc(2*_n,sizeof(_type_));
_BinIndexTree2=(_type_ *)calloc(2*_n,sizeof(_type_));
}
TreeArray(_type_ *arr,int n){
_n=n;
_BinIndexTree1=(_type_ *)calloc(2*_n,sizeof(_type_));
_BinIndexTree2=(_type_ *)calloc(2*_n,sizeof(_type_));
for(int i=1;i<=n;++i){
add(i,arr[i]);
}
}
void build(int n){ //双数组 区间修改、区间查询
_n=n;
_BinIndexTree1=(_type_ *)calloc(2*_n,sizeof(_type_));
_BinIndexTree2=(_type_ *)calloc(2*_n,sizeof(_type_));
long long tmp,pre=0;
for(int i=1;i<=n;++i){
scanf("%lld",&tmp);
add(i,(_type_)(tmp-pre));
pre=tmp;
}
}
private: void add(int pos,_type_ x){ //tree[pos]+=x
for(int i=pos;i<=_n;i+=(i&-i)){
_BinIndexTree1[i]+=x;
_BinIndexTree2[i]+=x*(pos-1);
}
}
public: void add(int left,int right,_type_ x){ //tree[left~right]+=x 区间修改
return add(left,x),add(right+1,-x);
}
private: _type_ sum(int pos){ //sum[1~pos]
_type_ res=0;
for(int i=pos;i;i-=(i&-i)){
res+=(_BinIndexTree1[i]*pos-_BinIndexTree2[i]);
}
return res;
}
public: _type_ sum(int left,int right){ //区间查询
return sum(right)-sum(left-1);
}
void show(){
for(int i=1;i<=_n;++i){
printf("%d ",_BinIndexTree1[i]);
}putchar('\n');
for(int i=1;i<=_n;++i){
printf("%d ",_BinIndexTree2[i]);
}
}
};
int main(){
int n,q;
scanf("%d%d",&n,&q);
TreeArray<long long>itr;
itr.build(n);
itr.show();cout<<endl;
while(q--){
int opt,a,b,k;
scanf("%d",&opt);
if(opt==1){
scanf("%d%d%d",&a,&b,&k);
itr.add(a,b,k);
}else{
scanf("%d%d",&a,&b);
printf("%lld\n",itr.sum(a,b));
}
itr.show();cout<<endl;
}
return 0;
}
图
dijkstra
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <vector>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <list>
#define INF 0x3f3f3f3f
using namespace std;
struct edge{
int to;
long long val;
edge(int _v,long long _w):to(_v),val(_w){}
bool operator < (const edge &p)const{
return to<p.to||(to==p.to&&val<p.val);
}
};
int n,m; //n:vertices' number m:edges' number
vector<vector<edge> >edges;
long long *dis;
typedef pair<long long,int> P; //first:distance second:to No. for heap in dijkstra
void dijkstra(int start=1){
priority_queue<P,vector<P>,greater<P> > ique;
dis=new long long [n+1];
memset(dis,0x3f,(n+1)*sizeof(long long));
dis[start]=0;
ique.push(P(0,start));
while(!ique.empty()){
P p=ique.top();
ique.pop();
int v=p.second;
if(dis[v]<p.first)continue;
for(int i=0;i<edges[v].size();++i){
edge e=edges[v][i];
if(dis[e.to]>dis[v]+e.val){
dis[e.to]=dis[v]+e.val;
ique.push(P(dis[e.to],e.to));
}
}
}
}
void showEdges(){
cout<<endl;
for(int i=1;i<=n;++i){
for(int j=0;j<edges[i].size();++j){
printf("%d %d %d\n",i,edges[i][j].to,edges[i][j].val);
}
}
}
void showDis(){
for(int i=1;i<n;++i){
printf("%lld ",dis[i]);
}printf("%lld\n",dis[n]);
}
int main(){
int start;
scanf("%d%d%d",&n,&m,&start);
//make graph
int v1,v2;long long wei;
edges.resize(n+1);
for(int i=0;i<m;++i){
scanf("%d%d%lld",&v1,&v2,&wei);
edges[v1].push_back(edge(v2,wei));
//edges[v2].push_back(edge(v1,wei)); //undirected
}
for(int i=1;i<=n;++i){
sort(edges[i].begin(),edges[i].end());
}
dijkstra(start);
showDis();
return 0;
}
基于一定标准的图及图上MST、割点、强连通、缩点、LCA
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <vector>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <list>
#include <bitset>
#define INF 0x3f3f3f3f
using namespace std;
//第一次使用请注意修改 TODO 部分函数
class UnionFindSet{
public:
int *_par;
long long *_num;
UnionFindSet(int n=10000){
_par=NULL;_num=NULL;
build(n);
}
void build(int n=10000){
if(_par) free(_par);
_par=new int[n+1];
if(_num) free(_num);
_num=new long long[n+1];
for(int i=0;i<=n;++i) _par[i]=i,_num[i]=1;
}
int root(int x){
int r=x,tmp;
while(r!=_par[r]) r=_par[r];
while(x!=r){
tmp=_par[x];_par[x]=r;x=tmp;
}
return x;
}
bool Union(int a,int b){
int ap=root(a),bp=root(b);
if(ap==bp) return false;
if(ap<bp){ //ap<-bp
_par[bp]=ap;
_num[ap]+=_num[bp];
}else{
_par[ap]=bp;
_num[bp]+=_num[ap];
}
return true;
}
void clear(){
free(_par);free(_num);_par=NULL;_num=NULL;build();
}
};
template <typename _type_=long long>//recommmand long long or double
class Graph{
private:
struct node_que{//for priority_queue in function "span_prim","span_kurskal"
int from,to;
_type_ val;
node_que(int _from,int _to,_type_ _w):from(_from),to(_to),val(_w){}
bool operator >(const node_que &p)const{
return val>p.val;
}
};
struct edge{//for edges
int to;
_type_ val;
edge(int _v,_type_ _w=(_type_)1):to(_v),val(_w){}
};
public:
//[1,ver_num] (begin from 1/点的编号从1开始)
int ver_num,edge_num; //vertices' number edges' number
vector<vector<edge> >edges;
vector<vector<edge> >spantree;
bool undirected; //undirected graph/无向图
vector<int>cutver; //cut vertex/articulation point/割点
vector<vector<int> >compress_edges; //compressed-edges/经过缩点后的图,
vector<vector<int> >contain; //compressed-point contains points/缩点后各点包含的/强连通图内的点
//scg_sum compressed-points number/缩点后的点数
//color 各点对应的颜色
/****************基础函数部分*****************/
Graph(){
initial();
}
public:void initial(){
ver_num=0;edge_num=0;
edges.clear();
spantree.clear();
undirected=true;
cutver.clear();
_dfn=_low=_instack=istack=color=NULL;_cnt=scg_sum=ttop=0;
compress_edges.clear();
}
public:void buildGraph(int n,int m){
//TODO
//you should edit here, avoid vertice 0
undirected=true;
ver_num=n;edge_num=m;
edges.resize(n+1);
for(int i=0;i<m;++i){
int a,b;double w;
scanf("%d%d",&a,&b);
//scanf("%lf",&w);
w=0;
//a,b>=1 attention
edges[a].push_back(edge(b,(_type_)w));
if(undirected) edges[b].push_back(edge(a,(_type_)w));
}
}
public:void buildTree(int n,int m){
//TODO
//you should edit here, avoid vertice 0
ver_num=n;edge_num=m;
edges.resize(n+1);
for(int i=0;i<m;++i){
int a,b;double w;
scanf("%d%d%lf",&a,&b,&w);
//a,b>=1 attention
edges[a].push_back(edge(b,(_type_)w));
if(undirected)edges[b].push_back(edge(a,(_type_)w));
spantree[a].push_back(edge(b,(_type_)w));
if(undirected)spantree[b].push_back(edge(a,(_type_)w));
}
}
/****************基础函数部分结束*****************/
/****************生成树部分*****************/
public:_type_ span_prim(int start=1){//mlogn
//return sum of edges or -1 when graph isn't connnected, "spantree" will span with points connected to point "start"
if(ver_num==0) return (_type_)-1;
_type_ res=0;
spantree.clear();
spantree.resize(ver_num+1);
priority_queue<node_que,vector<node_que>,greater<node_que> > ique;
int *vis=(int*)calloc(ver_num+1,sizeof(int));
_type_ *dis=(_type_*)malloc((ver_num+1)*sizeof(_type_));
memset(dis,0x3f,(ver_num+1)*sizeof(_type_));
ique.push(node_que(0,start,(_type_)0));
while(!ique.empty()){
node_que tmp=ique.top();ique.pop();
if(vis[tmp.to]) continue;
int u=tmp.to;
res+=tmp.val;
if(u!=start){
spantree[tmp.from].push_back(edge(u,tmp.val));
if(undirected)spantree[u].push_back(edge(tmp.from,tmp.val));
}
vis[u]=1;
for(int i=0;i<edges[u].size();++i){
if(!vis[edges[u][i].to]){
ique.push(node_que(u,edges[u][i].to,edges[u][i].val));
dis[edges[u][i].to]=min(dis[edges[u][i].to],edges[u][i].val);
}
}
}
for(int i=1;i<=ver_num;++i) if(!vis[i]) return (_type_)-1;
return res;
}
public:_type_ span_kurskal(){//mlogm
//return sum of edges or -1 when graph isn't connnected, "spantree" will be nothing
if(ver_num==0) return (_type_)-1;
_type_ res=0;
spantree.clear();
spantree.resize(ver_num+1);
priority_queue<node_que,vector<node_que>,greater<node_que> > ique;
int *vis=(int*)calloc(ver_num+1,sizeof(int));int left=ver_num;
UnionFindSet iset(ver_num);
for(int i=1;i<=ver_num;++i){
for(int j=0;j<edges[i].size();++j){
ique.push(node_que(i,edges[i][j].to,edges[i][j].val));
}
}
while(!ique.empty()){
node_que tmp=ique.top();ique.pop();
if(iset.Union(tmp.from,tmp.to)){
res+=tmp.val;
spantree[tmp.from].push_back(edge(tmp.to,tmp.val));
if(undirected)spantree[tmp.to].push_back(edge(tmp.from,tmp.val));
if(!vis[tmp.from]) vis[tmp.from]=1,--left;
if(!vis[tmp.to]) vis[tmp.to]=1,--left;
}
}
if(left){spantree.clear();return (_type_)-1;}
return res;
}
/*****************生成树部分结束*****************/
//割点与连通图共用变量:
private:int *_dfn,*_low,_cnt;
/*****************割点部分*****************/
private:void dfs_cutver(int from,int cur){//O(n+m)
_dfn[cur]=_low[cur]=++_cnt;
int kids=0,flag=0;
for(int i=0;i<edges[cur].size();++i){
int nx=edges[cur][i].to;
if(!_dfn[nx]){
++kids;
dfs_cutver(cur,nx);
_low[cur]=min(_low[cur],_low[nx]);
if(from==cur&&kids==2&&!flag) cutver.push_back(cur),flag=1;
else if(from!=cur&&_low[nx]>=_dfn[cur]&&!flag) cutver.push_back(cur),flag=1;
}
else if(from!=nx){
_low[cur]=min(_low[cur],_dfn[nx]);
}
}
}
public:int getCutVertex(){//O(n+m)
//return cut vertexs' number
if(ver_num==0) return -1;
_dfn=(int*)calloc(ver_num+1,sizeof(int));_low=(int*)calloc(ver_num+1,sizeof(int));_cnt=0;
for(int i=1;i<=ver_num;++i) if(!_dfn[i]) dfs_cutver(i,i);
free(_dfn);free(_low);_cnt=0;_dfn=_low=NULL;
sort(cutver.begin(),cutver.begin()+cutver.size());
return cutver.size();
}
/*****************割点部分结束*****************/
/*****************强连通图部分*****************/
private:int *_instack;int *istack;int ttop;
public:int *color;int scg_sum;
private:void dfs_scg(int cur){//O(n+m)
_dfn[cur]=_low[cur]=++_cnt;
_instack[cur]=1;
istack[ttop++]=cur;
for(int i=0;i<edges[cur].size();++i){
int nx=edges[cur][i].to;
if(!_dfn[nx]){
dfs_scg(nx);
_low[cur]=min(_low[cur],_low[nx]);
}else if(_instack[nx]){
_low[cur]=min(_low[cur],_dfn[nx]);
}
}
if(_dfn[cur]==_low[cur]){
++scg_sum;
while(istack[ttop]!=cur){
color[istack[--ttop]]=scg_sum;
_instack[ttop]=0;
contain[scg_sum].push_back(_instack[ttop]);
}
color[cur]=scg_sum;
_instack[cur]=0;
--ttop;
contain[scg_sum].push_back(cur);
}
}
public:int getSConnectedG(){//O(n+m)
//return points' number of Strongly Connected Graph
if(ver_num==0) return -1;
_dfn=(int*)calloc(ver_num+1,sizeof(int));_low=(int*)calloc(ver_num+1,sizeof(int));_cnt=0;
_instack=(int*)calloc(ver_num+1,sizeof(int));scg_sum=0;istack=(int*)calloc(ver_num+1,sizeof(int));ttop=0;
if(color)free(color),color=NULL;
color=(int*)calloc(ver_num+1,sizeof(int)); //color\scg_sum 不释放
contain.resize(ver_num+1);
for(int i=1;i<=ver_num;++i) if(!_dfn[i]) dfs_scg(i);
contain.resize(scg_sum+1);
free(_dfn);free(_low);_cnt=0;_dfn=_low=NULL;
free(istack);ttop=0;istack=NULL;
free(_instack);_instack=NULL;
return scg_sum;
}
/*****************强连通图部分结束*****************/
/*****************缩点部分*************************/
public:bool getCompressedG(){//O(n+m)
if(scg_sum<=0||color<=0) if(getSConnectedG()<=0) return false;
compress_edges.resize(scg_sum+1);
for(int i=1;i<=ver_num;++i){
for(int j=0;j<edges[i].size();++j){
int nxt=edges[i][j].to;
if(color[i]!=color[nxt]){
compress_edges[color[i]].push_back(color[nxt]);
}
}
}
vector<int>::iterator new_end;
for(int i=1;i<=scg_sum;++i){
sort(compress_edges[i].begin(),compress_edges[i].end());
new_end=unique(compress_edges[i].begin(),compress_edges[i].end());
compress_edges[i].erase(new_end,compress_edges[i].end());
}
return true;
}
/*****************缩点部分结束*****************/
/*****************LCA部分**********************/
/*****************LCA部分结束******************/
};
int main(){
Graph<long long>mst;
int n,m;
scanf("%d%d",&n,&m);
mst.buildGraph(n,m);
/*
cout<<"MST all edges:"<<endl;
for(int i=0;i<mst.spantree.size();++i){
for(int j=0;j<mst.spantree[i].size();++j){
cout<<i<<' '<<mst.spantree[i][j].to<<' '<<mst.spantree[i][j].val<<endl;
}
}
for(int i=0;i<mst.edges.size();++i){
for(int j=0;j<mst.edges[i].size();++j){
cout<<i<<' '<<mst.edges[i][j].to<<' '<<mst.edges[i][j].val<<endl;
}
}*/
mst.getCompressedG();
for(int i=1;i<=mst.scg_sum;++i){
cout<<i<<": ";
for(int j=0;j<mst.compress_edges[i].size();++j){
cout<<mst.compress_edges[i][j]<<' ';
}cout<<endl;
}
return 0;
}
串
LCS、LIS
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <cmath>
#include <complex>
#include <algorithm>
#include <cstring>
#include <vector>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <list>
#define Swap(a,b) {a=a^b;b=b^a;a=a^b;}
#define INF 0x3f3f3f3f
#define INFll 0x3f3f3f3f3f3f3f3fll
using namespace std;
class Graph{
public:
vector<vector<int> >edge;
int vertices;
private:
struct ques{
int snum,lca,tar;
ques(){
snum=0;lca=0;tar=0;
}
ques(int _num,int _tar):snum(_num),tar(_tar){}
};
vector<int>parent;
vector<int>vis;
vector<list<ques> >query;
vector<int>ans;
public:
Graph(){
edge.clear();parent.clear();vis.clear();query.clear();ans.clear();vertices=0;
}
Graph(int n):vertices(n){
edge.clear();parent.clear();vis.clear();query.clear();ans.clear();vertices=n;
edge.resize(n+1);
}
void resize(int n){
vertices=n;edge.clear();edge.resize(n+1);
}
void build(){
/** you need to edit it
input:
edge[][]
*/
for(int i=0;i<vertices-1;++i){
int a,b;
scanf("%d%d",&a,&b);
edge[a].push_back(b);
edge[b].push_back(a);
}
}
private:
int root(int x){
int ans=x,tmp;
while(parent[ans]!=ans) ans=parent[ans];
while(x!=ans){
tmp=x;
x=parent[x];
parent[tmp]=ans;
}
return ans;
}
void Tarjan_dfs(int curpos,int fa){
int aim;
for(int i=0;i<(int)edge[curpos].size();++i){
aim=edge[curpos][i];
if(aim==fa) continue;
Tarjan_dfs(aim,curpos);
parent[aim]=curpos;
vis[aim]=1;
}
for(list<ques>::iterator it=query[curpos].begin();it!=query[curpos].end();++it){
aim=it->tar;
if(vis[aim]){
ans[it->snum]=root(aim);
}
}
query[curpos].clear();
}
public:
void Tarjan(int query_num,int rt=1){
parent.resize(vertices+1); for(int i=0;i<=vertices;++i) parent[i]=i;
vis.resize(vertices+1,0);
query.clear();query.resize(vertices+1);
ans.resize(query_num);
for(int i=0;i<query_num;++i){
int a,b;
scanf("%d%d",&a,&b);
if(a==b){
ans[i]=a;
}else{
query[a].push_back(ques(i,b));
query[b].push_back(ques(i,a));
}
}
Tarjan_dfs(rt,0);
}
void showAns(){
//you need to edit it
for(int i=0;i<(int)ans.size();++i) printf("%d\n",ans[i]);
}
};
int main(){
int n,m,rot;
scanf("%d%d%d",&n,&m,&rot);
Graph g(n);
g.build();
g.Tarjan(m,rot);
g.showAns();
return 0;
}