模板库:
字典树,数组实现(hdu1251)
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e6+10,maxm=2e6+10;
struct Trie{
#define base 'a'
int next[maxn][27],size,cnt[maxn];
void init(){
size=1;
memset(next[0],0,sizeof next[0]);
}
void add(char *str,int len=0){
int cur=0,k;
if(len==0) len=strlen(str);
for(int i=0;i<len;++i){
k=str[i]-base;
if(!next[cur][k]){
memset(next[size],0,sizeof next[size]);
cnt[size]=0;
next[cur][k]=size++;
}
cnt[next[cur][k]]++;
cur=next[cur][k];
}
}
int find(char *str,int len=0){
if(len==0) len=strlen(str);
int cur=0,k;
for(int i=0;i<len;i++){
k=str[i]-base;
if(next[cur][k]) cur=next[cur][k];
else return 0;
}
return cnt[cur];
}
}trie;
int main() {
trie.init();
char str[100];
while(1){
gets(str);
if(str[0]=='\0') break;
trie.add(str);
}
while(~scanf("%s",str)){
printf("%d\n",trie.find(str));
}
return 0;
}
FFT 完整模板 自定义虚数
struct cp {
double x, y;
cp(double a=0, double b=0):x(a), y(b) {}
inline cp operator +(cp &b) {return cp(x+b.x, y+b.y);}
inline cp operator -(cp &b) {return cp(x-b.x, y-b.y);}
inline cp operator *(cp &b) {return cp(x*b.x-y*b.y, x*b.y+y*b.x);}
inline cp conj() {return cp(x, -y);}
};
struct FFT {
int size, rev[maxn];
void init(int lim) {
size=1;int k=0;
while(size<lim) size<<=1, k++;
for(int i=0; i<size; i++) {
for(int j=0; j<k; j++) if(i&(1<<j)) rev[i] |= (1<<(k-1-j));
}
}
void dft(cp *a, int flag) {
for(int i=0; i<size; i++) if(i<rev[i]) swap(a[i], a[rev[i]]);
for(int l=2; l<=size; l<<=1) {
int m=l>>1;
cp wn=(cp){cos(2*PI/l), flag*sin(2*PI/l)};
for(cp *p=a; p!=a+size; p+=l) {
cp w=(cp){1,0};
for(int k=0; k<m; k++) {
cp t = w*p[k+m];
p[k+m] = p[k] - t;
p[k] = p[k] + t;
w=w*wn;
}
}
}
if(flag==-1) for(int i=0; i<size; i++) a[i].x/=size;
}
} fft;
欧拉函数
ll euler(ll n) {
ll res=n,a=n;
for(int i=2; i*i<=a; i++) {
if(a%i==0) {
res=res/i*(i-1);
while(a%i==0) a/=i;
}
}
if(a>1) res=res/a*(a-1);
return res;
}
int euler[maxn];
void geteul() {
euler[1]=1;
int n=maxn-10;
for(int i=2; i<=n; i++) euler[i]=i;
for(int i=2; i<=n; i++)if(euler[i]==i)
for(int j=i; j<=n; j+=i)
euler[j]=euler[j]/i*(i-1);
}
打表 莫比乌斯函数
int mu[maxn],prime[maxn],nump;
bool isp[maxn];
void getmu(){
mu[1]=1;
int n=maxn-5;
for(int i=2;i<=n;i++){
if(!isp[i])prime[++nump]=i,mu[i]=-1;
for(int j=1;j<=nump&&prime[j]*i<=n;j++){
isp[i*prime[j]]=1;
if(i%prime[j]==0){mu[i*prime[j]]=0;break;}
else mu[i*prime[j]]=-mu[i];
}
}
}
素数筛.米勒罗宾判素数,需要快速乘
ll prime[maxn];
ll count_prime
ll init_prime(ll n){
ll count=0;
bool vis[n+1];
for(int i=2;i<=n;++i)vis[i] = true;
vis[2] = true;
for(int j=2;j<=n;++j)
if(vis[j]==true)
for(int m=2;j*m<=n;++m)vis[j*m] = false;
for(int i=2;i<=n;++i)
if(vis[i]==true)
prime[count++]=i;
return count;
}
bool test(ll n,ll a,ll d) {
if(n==2||n==a) return true;
if((n&1)==0) return false;
while(!(d&1)) d>>=1;
ll t=powmod(a,d,n);
while(d!=n-1&&t!=1&&t!=n-1){
t=mul_mod(t,t,n);
d<<=1;
}
return (t==n-1||(d&1)==1);
}
bool isprime(ll n) {
if(n<2) return false;
rep(i,0,count_prime) if(!test(n,prime[i],n-1)) return false;
return true;
}
初等数论板-加入快速乘,快速乘快速幂
const ll mod=1e9+7;
ll gcd_mod(ll a,ll b,ll c=mod){while(b)b=((a%b)%c+((a=b)-b)%c)%c;return a;}
ll lcm_mod(ll a,ll b,ll c=mod){return (a/gcd(a,b)*b)%mod;}
ll pow_mod(ll a,ll b,ll c=mod,ll ans=1){while(b){if(b&1) ans=(a*ans)%c;a=(a*a)%c,b>>=1;}return ans;}
ll inv_mod(ll a){return pow_mod(a,mod-2);}
ll mul_mod(ll a, ll b, ll c=mod) {if(a<b)swap(a,b);ll res=0;while (b) {if(b & 1)res=(res+a)%n;a = (a + a) % n;b>>=1;}return res;}
ll pow_mul_mod(ll a, ll b, ll n=mod) {ll res=1;while(b) {if(b&1)res=mul_mod(res,a,n);a=mul_mod(a,a,n);b>>=1;}return res;}
Dfs查找欧拉路径/回路
int vis[maxn];
int cnt;
struct node {
int to,flag,id,next;
}e[maxm];
int head[maxn],nume,deg[maxn];
inline void _add(int a,int b,int c){
e[++nume]=(node){b,1,c,head[a]};
head[a]=nume;
}
inline void add(int a,int b,int c){
addnode(a,b,c);addnode(b,a,-c);
}
vector<int> ans[maxn];
void dfs(int now){
vis[now]=1;
for(int i=head[now];i;i=e[i].next){
if(!e[i].flag) continue;
e[i].flag=e[i^1].flag=0;
dfs(e[i].to);
ans[cnt].push_backe(-e[i].id);
}
}
void solve(){
rep(i,1,n){
if(!vis[i]&°[i]&1) {
cnt++;
dfs(i);
}
}
rep(i,1,n){
if(!vis[i]&°[i]){
cnt++;
dfs(i);
}
}
}
平衡树之Treap,插入,删除,zag,zig,更新,求第k大,求val名次,求前驱,求后继
#define nd treap[now]
#define ndl treap[treap[now].l]
#define ndr treap[treap[now].r]
#define ndt treap[tmp]
struct node {
int l,r,val,num,size,rnd;
}treap[maxn];
int cnt,root,ans;
inline void resize(int now){
nd.size=ndl.size+ndr.size+nd.num;
}
inline void rturn(int &now){
int tmp=nd.l;
nd.l=ndt.r,ndt.r=now;
ndt.size=nd.size;
resize(now);
now=tmp;
}
inline void lturn(int &now){
int tmp=nd.r;
nd.r=ndt.l,ndt.l=now;
ndt.size=nd.size;
resize(now);
now=tmp;
}
void insert(int &now,int val){
if(!now) {
now=++cnt;
nd=(node){0,0,val,1,1,rand()};
return ;
}
nd.size++;
if(val==nd.val)nd.num++;
else if(val>nd.val){
insert(nd.r,val);
if(ndr.rnd<nd.rnd) lturn(now);
}else{
insert(nd.l,val);
if(ndl.rnd<nd.rnd) rturn(now);
}
}
void erase(int &now,int val){
if(!now) return ;
if(val==nd.val){
if(nd.num>1){
nd.num--,nd.size--;
return ;
}
if(nd.r*nd.l==0) now=nd.l+nd.r;
else {
if(ndl.rnd<ndr.rnd) rturn(now);
else lturn(now);
erase(now,val);
}
}else {
nd.size--;
if(val>nd.val) erase(nd.r,val);
else erase(nd.l,val);
}
}
int query_rank(int now,int val){
if(!now) return 0;
if(val==nd.val)return ndl.size+1;
if(val>nd.val) return ndl.size+nd.num+query_rank(nd.r,val);
return query_rank(nd.l,val);
}
int query_val(int now,int rank){
if(!now) return 0;
if(rank<=ndl.size) return query_val(nd.l,rank);
if(rank-ndl.size<=nd.num) return nd.val;
return query_val(nd.r,rank-ndl.size-nd.num);
}
int query_pre(int now,int val){
if(!now) return ans;
if(val<=nd.val) return query_pre(nd.l,val);
ans=nd.val;
return query_pre(nd.r,val);
}
int query_sub(int now,int val){
if(!now) return ans;
if(val>=nd.val) return query_sub(nd.r,val);
ans=nd.val;
return query_sub(nd.l,val);
}
数列分块单点修改
int size;
ll num[maxn],tag[maxn];
int id[maxn];
void update(int s,int t,ll x){
for(int i=s;i<=min(id[s]*size,t);i++)
num[i]+=x;
if(id[s]!=id[t]){
for(int i=(id[t]-1)*size+1;i<=t;i++)
num[i]+=x;
}
for(int i=id[s]+1;i<=id[t]-1;i++){
tag[i]+=x;
}
}
void init(){
size=sqrt(n);
for(int i=1;i<=n;i++) id[i]=(i-1)/size+1;
}
主席树求区间第K大
#include <bits/stdc++.h>
#define nd seg[now]
#define ndp seg[pre]
#define mid ((s+t)>>1)
using namespace std;
const int maxn=1e5+10;
int casn,n,m,k;
int num[maxn],rt[maxn],size;
vector<int>pos;
struct node{
int l,r,sum;
}seg[maxn*20];
void maketree(int s=1,int t=n,int &now=rt[0]){
now=++size;nd={s,t,0};
if(s==t) return ;
maketree(s,mid,nd.l);maketree(mid+1,t,nd.r);
}
void update(int &now,int pre,int k,int s=1,int t=n){
now=++size;nd=ndp,nd.sum++;
if(s==t) return ;
if(k<=mid)update(nd.l,ndp.l,k,s,mid);
else update(nd.r,ndp.r,k,mid+1,t);
}
int query(int now,int pre,int k,int s=1,int t=n){
if(s==t) return s;
int sum=seg[ndp.l].sum-seg[nd.l].sum;
if(k<=sum) return query(nd.l,ndp.l,k,s,mid);
else return query(nd.r,ndp.r,k-sum,mid+1,t);
}
int main(){
scanf("%d",&casn);
while(casn--){
scanf("%d%d",&k,&m);
pos.clear();
size=0;
for(int i=1;i<=k;i++){
scanf("%d",num+i);
pos.push_back(num[i]);
}
sort(pos.begin(),pos.end());
pos.erase(unique(pos.begin(),pos.end()),pos.end());
n=pos.size();
maketree(1,n,rt[0]);
for(int i=1;i<=k;i++){
int id=lower_bound(pos.begin(),pos.end(),num[i])-pos.begin()+1;
update(rt[i],rt[i-1],id);
}
while(m--){
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
printf("%d\n",pos[query(rt[a-1],rt[b],c)-1]);
}
}
return 0;
}
RMQ-树状数组
int bt[maxn],num[maxn];
#define lb(x) (x&(-x))
void upd(int pos, int x) {
num[pos] = x;
for(int i = pos; i <= n; i += lb(i)) {
bt[i] = x;
for(int j = 1; j < lb(i); j <<= 1) {
bt[i] = bt[i] > bt[i-j] ? bt[i] : bt[i-j];
}
}
}
void init() {
memset(bt, 0, sizeof bt);
for(int i = 1; i <= n; i++) {
bt[i] = num[i];
for(int j = 1; j <lb(i); j <<= 1)
bt[i] = bt[i] > bt[i-j] ? bt[i] : bt[i-j];
}
}
int find(int l, int r) {
int ans = 0;
while(1) {
ans = ans > num[r] ? ans : num[r];
if(r == l) break;
for(r -= 1; r-l >= lb(r); r -= lb(r))
ans = ans > bt[r] ? ans : bt[r];
}
return ans;
}
RMQ-ST表
int table[maxn][1<<18];
void makest(int n) {
for(int i=1; i<=n; i++)
table[i][0]=A[i];
int m=(int)(log((double)n)/log(2.0)));
for(int j=1; j<=m; j++) {
for(int i=1; i+(1<<j)-1<=n; i++)
table[i][j]=min(table[i][j-1],table[i+(1<<j)][j-1]);
}
}
int stfind(int l,int r) {
int k=(int)(log(double(r-l+1))/log(2.0));
return min(table[l][k],table[r-(1<<k)+1][k];
}
带删除操作的并查集
#define same(a,b) (find(a)==find(b))
int pre[maxn],id[maxn];
int numid;
int fd(int a) {
return pre[a]==a?a:pre[a]=find(pre[a]);
}
int find(int a){return fd(id[a])};
void unite(int a,int b){
a=find(id[a]),b=find(id[b]);
pre[b]=a;
}
void remove(int now){
int pos=find(id[now]);
id[now]=++numid;
pre[numid]=numid;
}
doubly树上倍增
struct node {
int to,next;
} e[maxm];
int head[maxn],nume;
void add(int a,int b) {
e[++nume]=(node) {b,head[a]};
head[a]=nume;
}
int dt[31][maxn],dep[maxn];
void ldfs(int now,int pre){
for(int i=head[now];i;i=e[i].next){
int to=e[i].to;
if(to!=pre&&to!=dt[0][now]){
dep[to]=dep[now]+1;
dt[0][to]=now;
ldfs(to,now);
}
}
}
int lca(int a,int b){
if(dep[a]<dep[b]) swap(a,b);
int dis=dep[a]-dep[b];
for(int i=0;(dis>>i);i++){
if((dis>>i)&1) a=dt[i][a];
}
if(a==b) return a;
for(int i=20;i>=0;i--)
if(dt[i][a]!=dt[i][b]){
a=dt[i][a],b=dt[i][b];
}
return dt[0][a];
}
void init(int root){
dep[root]=1;
ldfs(root,root);
for(int i=1;(1<<i)<=n;i++)
for(int j=1;j<=n;j++)
dt[i][j]=dt[i-1][dt[i-1][j]];
}
常数优化高级指令
#pragma comment(linker, "/stack:200000000")
#pragma GCC optimize("Ofast")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
#pragma GCC optimize("unroll-loops")
KMP
int table[maxn][1<<18];
void makest(int n) {
for(int i=1; i<=n; i++)
table[i][0]=A[i];
int m=(int)(log((double)n)/log(2.0)));
for(int j=1; j<=m; j++) {
for(int i=1; i+(1<<j)-1<=n; i++)
table[i][j]=min(table[i][j-1],table[i+(1<<j)][j-1]);
}
}
int stfind(int l,int r) {
int k=(int)(log(double(r-l+1))/log(2.0));
return min(table[l][k],table[r-(1<<k)+1][k];
}
矩阵,重载运算符+-*,清空与赋值函数,成员函数:clear清空 e转化为单位矩阵 fill用数字或者数组填充,pow快速幂函数 带取模
struct node {int a,b;ll x[maxn][maxn];
void clear(int n=0,int m=0){a=n,b=m;memset(x,0,sizeof x);}
void e(int n){a=b=n;for(int i=0;i<n;i++)x[i][i]=1;}
void fill(ll xx=0){for(int i=0;i<a;i++)for(int j=0;j<b;j++)x[i][j]=xx;}
void fill(int n,int m,ll xx[][maxn]){a=n,b=m;for(int i=0;i<n;i++)for(int j=0;j<m;j++)x[i][j]=xx[i][j];}
node operator *(node &m){node ans;ans.clear(a,m.b);
for(int i=0;i<a;i++)for(int j=0;j<m.b;j++)for(int k=0;k<b;k++)if(x[i][k]&&m.x[k][j])
ans.x[i][j]=(mod+ans.x[i][j]+(x[i][k]*m.x[k][j]+mod)%mod)%mod;
return ans;}
node operator +(node &m){node ans;ans.clear(a,b);
for(int i=0;i<a;i++)for(int j=0;j<b;j++)ans.x[i][j]=(x[i][j]+m.x[i][j]+mod)%mod;
return ans;}
node operator -(node &m){node ans;ans.clear(a,b);
for(int i=0;i<a;i++)for(int j=0;j<b;j++)ans.x[i][j]=(x[i][j]-m.x[i][j]+mod)%mod;
return ans;}
node pow(ll p){node ans;ans.clear();ans.e(a);node t;t.clear();t.fill(a,b,x);
while(p){if(p&1) ans=t*ans;t=t*t;p>>=1;}return ans;}
};
单调栈
int stk[maxn];//向左的第一个最小数字的位置
void mstk(int a[]=num,int l[]=pos,int len=n){
int top=0;
for(int i=1;i<=n;i++){
while(top&&a[stk[top]>=a[i]]) top--;
if(top) l[i]=stk[top];
else l[i]=0;
stk[++top]=i;
}
}
SPFA最小费用最大流,朴素无优化,复杂度$O(EV^2)$
struct node {
int pre,to,cap,cost,next;
}e[maxm];
int head[maxn],nume,inq[maxn],sum,ans;
int que[maxn],pre[maxn],dis[maxn];
int num[maxn],S,T;
inline void addedge(int a,int b,int c,int d){
e[++nume]={a,b,c,d,head[a]};
head[a]=nume;
}
inline void add(int a,int b,int c,int d){
addedge(a,b,c,d);addedge(b,a,0,-d);
}
bool spfa(){
for(int i=0;i<=T;i++)dis[i]=INF;
dis[S]=que[0]=S;
int top=0,end=1;
while(top!=end){
int now=que[top++];top%=maxn;
for(int i=head[now];i;i=e[i].next){
if(e[i].cap&&dis[e[i].to]>dis[now]+e[i].cost){
pre[e[i].to]=i;
dis[e[i].to]=dis[now]+e[i].cost;
if(!inq[e[i].to]){
inq[e[i].to]=true;
que[end++]=e[i].to;end%=maxn;
}
}
}
inq[now]=false;
}
return dis[T]!=INF;
}
void dfs(){
int flow=INF;
for(int i=pre[T];i;i=pre[e[i].pre]) flow=min(flow,e[i].cap);
for(int i=pre[T];i;i=pre[e[i].pre]) {
e[i].cap-=flow;
e[i^1].cap+=flow;
ans+=e[i].cost*flow;
}
}
void mcf(){
ans=0;
while(spfa()) dfs();
}
int读入挂终极版Plus之改无可改:fread读取内存,每次移动指针减少寻址时间,需要输入Ctrl+Z或者用文件输入
struct io {char buf[1 << 26], *s;io() {fread(s = buf, 1, 1 << 26, stdin);}inline int read() {register int res = 0;while(*s < '0' || *s > '9') s++;while(*s >= '0' && *s <= '9') res = res * 10 + *s++ - '0';return res;}} ip;
#define read ip.read
最大流Dinic算法,复杂度上限$O(EV^2)$,朴素无优化
int to[maxm],cap[maxm],nex[maxm];
int head[maxn],S,T,nume,ans,dis[maxn];
int q[maxn];
void add(int a,int b,int c){
to[nume]=b,cap[nume]=c,nex[nume]=head[a];
head[a]=nume++;
to[nume]=a,cap[nume]=0,nex[nume]=head[b];
head[b]=nume++;
}
bool bfs(){
memset(dis,-1,sizeof dis);
int top=0,end=0;
q[end++]=S;
dis[S]=0;
while(top!=end){
int now=q[top++];top%=maxn;
for(int i=head[now];~i;i=nex[i])
if(dis[to[i]]==-1&&cap[i]){
dis[to[i]]=dis[now]+1;
q[end++]=to[i];end%=maxn;
}
}
return dis[T]!=-1;
}
int dfs(int now,int last){
if(now==T) return last;
int used=0,flow;
for(int i=head[now];~i;i=nex[i]){
if(cap[i]&&dis[to[i]]==dis[now]+1){
flow=last-used;
flow=dfs(to[i],min(flow,cap[i]));
used+=flow;
cap[i]-=flow;
cap[i^1]+=flow;
if(used==last) return last;
}
}
if(used==0) dis[now]=-1;
return used;
}
void dinic(){
ans=0;
while(bfs())ans+=dfs(S,0x3f3f3f3f);
}
int读入挂终极版:fread读取内存,每次需要单独输入Ctrl+Z作为结束输入
#define tpyeinput int
inline char nc() {static char buf[1000000],*p1=buf,*p2=buf;return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;}
inline void read(tpyeinput &sum) {char ch=nc();sum=0;while(!(ch>='0'&&ch<='9')) ch=nc();while(ch>='0'&&ch<='9') sum=(sum<<3)+(sum<<1)+(ch-48),ch=nc();}
inline void read(tpyeinput &num1,tpyeinput &num2){read(num1);read(num2);}
inline void read(tpyeinput &num1,tpyeinput &num2,tpyeinput &num3){read(num1);read(num2);read(num3);}
inline void read(tpyeinput &num1,tpyeinput &num2,tpyeinput &num3,tpyeinput &num4){read(num1);read(num2);read(num3);read(num4);}
最长不上升子序列和最长上升子序列的O(nlogn)算法 //合唱队列问题
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
int casn,n,m,k;
int num[maxn];
int dp[maxn];
int len;
int lwb(int now){
int l=0,r=len,ans=0;
while(l<r){
int mid=(l+r)>>1;
if(dp[mid]>=now) l=mid+1;
else r=mid;
}
return l;
}
int lwb2(int now){
int l=0,r=len;
while(l<r){
int mid=(l+r)>>1;
if(dp[mid]>=now) r=mid;
else l=mid+1;
}
return l;
}
int main(){
cin>>n;
for(int i=1;i<=n;i++) cin>>num[i];
for(int i=1;i<=n;i++){
if(dp[len]>=num[i]) dp[++len]=num[i];
else dp[lwb(num[i])]=num[i];
}
cout<<len<<endl;
len=0;
memset(dp,0,sizeof dp);
for(int i=1;i<=n;i++){
if(dp[len]<num[i]) dp[++len]=num[i];
else dp[lwb2(num[i])]=num[i];
}
cout<<len<<endl;
return 0;
}
int读入挂1,可判断文件末尾,重载函数可读入1-4个参数,返回值为是否成功读入
#define tpyeinput int
inline bool read(tpyeinput &num){int flag=1,ch=getchar();if(ch==EOF) return false;num=0;while(ch<'0'||ch>'9'){if(ch=='-') flag=-1;ch=getchar();}while(ch>='0'&&ch<='9'){num=num*10+ch-'0',ch=getchar();}num*=flag;return true;}
inline bool read(tpyeinput &num1,tpyeinput &num2){return read(num1)&&read(num2);}
inline bool read(tpyeinput &num1,tpyeinput &num2,tpyeinput &num3){return read(num1)&&read(num2)&&read(num3);}
inline bool read(tpyeinput &num1,tpyeinput &num2,tpyeinput &num3,tpyeinput &num4){return read(num1)&&read(num2)&&read(num3)&&read(num4);}
int读入挂2,返回值为读入值,无法判定文件末尾
#define tpyeinput int
inline tpyeinput read(){tpyeinput num=0,flag=1,ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-') flag=-1;ch=getchar();}while(ch>='0'&&ch<='9'){num=(num<<3)+(num<<1)+ch-'0',ch=getchar();}return flag*num;}
非递归最大公因数,最小公倍数,非递归快速幂,求逆元,带取模
const ll mod=1e9+7;
ll gcd(ll a,ll b,ll c=mod){while(b)b=((a%b)%c+((a=b)-b)%c)%c;return a;}
ll lcm(ll a,ll b,ll c=mod){return (a/gcd(a,b)*b)%mod;}
ll powmod(ll a,ll b,ll c=mod,ll ans=1){while(b){if(b&1) ans=(a*ans)%c;a=(a*a)%c,b>>=1;}return ans;}
ll inv(ll a){return powmod(a,mod-2);}
最大连续子矩阵/连续子段和
/*poj1050
把二维看成一维
先枚举行的起点和终点
再把起点行和终点行间每一列的数值压缩到每一个点上
然后求一个最长连续字段和
复杂度O(n^3)
*/
#include <string.h>
#include <stdio.h>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn=1e3+10;
const int maxm=1e6+10;
const int INF=0x3f3f3f3f;
#define ll long long
int casn,n,m,k;
int smax(int a[],int len){
int mx=0,sub=0;
for(int i=1;i<=len;i++){
sub=max(a[i],sub+a[i]);
mx=max(sub,mx);
}
return mx;
}
int arr[maxn];
int dp[maxn][maxn];
int main(){
#define test
#ifdef test
freopen("in.txt","r",stdin);freopen("out.txt","w",stdout);
#endif
while(~scanf("%d",&n)){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
scanf("%d",&dp[i][j]);
}
}
int ans=-INF;
for(int i=1;i<=n;i++){
memset(arr,0,sizeof arr);
for(int j=i;j<=n;j++){
for(int k=1;k<=n;k++){
arr[k]+=dp[j][k];
}
ans=max(ans,smax(arr,n));
}
}
printf("%d\n",ans);
}
#ifdef test
fclose(stdin);fclose(stdout);system("out.txt");
#endif
return 0;
}
tarjan双边强连通分量缩点,两次dfs求树的直径
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
const int maxm=1e6+10;
const int INF=0x3f3f3f3f;
typedef long long ll;
typedef unsigned long long ull;
#define tpyeinput int
inline bool read(tpyeinput &num){int flag=1,ch=getchar();if(ch==EOF) return false;num=0;while(ch<'0'||ch>'9'){if(ch=='-') flag=-1;ch=getchar();}while(ch>='0'&&ch<='9'){num=num*10+ch-'0',ch=getchar();}num*=flag;return true;}
inline bool read(tpyeinput &num1,tpyeinput &num2){return read(num1)&&read(num2);}
inline bool read(tpyeinput &num1,tpyeinput &num2,tpyeinput &num3){return read(num1)&&read(num2)&&read(num3);}
inline bool read(tpyeinput &num1,tpyeinput &num2,tpyeinput &num3,tpyeinput &num4){return read(num1)&&read(num2)&&read(num3)&&read(num4);}
struct node {int to,cost,next;}e[maxm],e2[maxm];int head[maxn],head2[maxn],nume,nume2;
void add(int a,int b,int c=1,node *eg=e,int &ne=nume,int hd[]=head){eg[++ne]=(node){b,c,hd[a]};hd[a]=ne;}
int casn,n,m,k;
int low[maxn],dfn[maxn],stk[maxn];
int ins[maxn];
int top,numc,numd,belong[maxn];
void tjdfs(int now,int pre) {
dfn[now]=low[now]=++numd;
stk[++top]=now;
ins[now]=1;
for(int i=head[now]; i; i=e[i].next) {
int to=e[i].to;
if(to==pre)continue;
if(ins[to]==0) tjdfs(to,now);
low[now]=min(low[now],low[to]);
}
if(low[now]==dfn[now]) {
numc++;
do {
belong[stk[top]]=numc;
ins[stk[top]]=-1;
} while(stk[top--]!=now);
}
}
void tjmake(){
for(int i=1;i<=n;i++){
int a=belong[i];
for(int j=head[i];j;j=e[j].next){
int to=e[j].to;
int b=belong[to];
if(a==b) continue;
add(a,b,1,e2,nume2,head2);
add(b,a,1,e2,nume2,head2);
}
}
}
inline void tjinit(){
numc=nume2=numd=0;
top=-1;
memset(ins,0,sizeof ins);
memset(dfn,0,sizeof dfn);
memset(head2,0,sizeof head);
memset(belong,0,sizeof belong);
memset(low,0,sizeof low);
memset(stk,0,sizeof stk);
}
inline void tarjan(){
tjinit();
for(int i=1;i<=n;i++) if(ins[i]==0){
tjdfs(i,-1);
}
tjmake();
}
int vis[maxn],cnt=0,pos,ans;
void dfs(int now,int dep=0){
vis[now]=1;
if(dep>cnt){
cnt=dep;
pos=now;
}
for(int i=head2[now];i;i=e2[i].next){
int to=e2[i].to;
if(!vis[to]) dfs(to,dep+1);
}
}
int main(){
//#define test
#ifdef test
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
read(casn);
while(casn--){
read(n,m);
memset(head,0,sizeof head);
nume=0;
for(int i=0;i<m;i++){
int a,b;read(a,b);
add(a,b);
add(b,a);
}
tarjan();
memset(vis,0,sizeof vis);
cnt=0;
pos=1;
dfs(1);
memset(vis,0,sizeof vis);
cnt=0;
dfs(pos);
cout<<numc-cnt-1<<endl;;
}
#ifdef test
fclose(stdin);
fclose(stdout);
system("out.txt");
#endif
return 0;
}
简单的tarjan强连通分量
int stk[maxn],top,cnt,dfn[maxn],low[maxn],numc,belong[maxn],vis[maxn];
struct node {int to,cost,next;}e[maxm];int head[maxn],nume;
void add(int a,int b,int c=1){e[++nume]=(node){b,c,head[a]};head[a]=nume;}
void tdfs(int now){
dfn[now]=low[now]=++cnt;
stk[top++]=now;
vis[now]=1;
for(int i=head[now];i;i=e[i].next){
int to=e[i].to;
if(!dfn[to]){tdfs(to);low[now]=min(low[now],low[to]);}
else if(vis[to]) low[now]=min(low[now],dfn[to]);
}
if(low[now]==dfn[now]){
numc++;
int to;
do{
to=stk[--top];
belong[to]=numc;
vis[to]=0;
}while(to!=now);
}
}
void tarjan(int numv=n){
for(int i=1;i<=numv;i++){
if(!dfn[i]) tdfs(i);
}
}
void ginit(){
nume=top=numc=cnt=0;
memset(head,0,sizeof head);
memset(dfn,0,sizeof dfn);
memset(low,0,sizeof low);
memset(belong,0,sizeof belong);
memset(vis,0,sizeof vis);
}//只计算强连通分量和归属
tarjan求无向图割点
void tdfs(int now,int pre){
low[now]=dfn[now]=++cnt;
int numt=0;
for(int i=head[now];i;i=e[i].next){
int to=e[i].t;
if(to==pre) continue;
if(!dfn[to]){
numt++;
tdfs(to,now);
low[now]=min(low[to],low[now]);
if(now!=pre&&low[to]>=dfn[now]){
cut[now]=1;
}
}else low[now]=min(low[now],dfn[to]);
}
if(now==pre&&numt>1) cut[now]=1;
}
非递归并查集路径压缩,按秩合并
int pre[maxn],rk[maxn];
int find(int a){
if(pre[a]==-1) return a;
int t,rt=a;
while(pre[rt]!=-1) rt=pre[rt];
while(a!=rt)t=pre[a],pre[a]=rt,a=t;
return rt;
}
#define same(a,b) (find(a)==find(b))
void unite(int a,int b){
a=find(a),b=find(b);
if(a==b) return;
if(rk[a]>rk[b])
pre[b]=a;
else {
pre[a]=b;
if(rk[a]==rk[b])
rk[b]++;
}
}
简单的并查集
int pre[maxn];
int find(int a){return !(~pre[a])?a:pre[a]=find(pre[a]);}
#define same(a,b) (find(a)==find(b))
#define unite(a,b) pre[find(b)]=find(a)
SPFA,SLF优化,链式前向星,数组循环队列
struct node {int to;int cost;int next;}e[maxm];int head[maxn],nume;
inline void add(int a,int b,int c=1){e[++nume]=(node){b,c,head[a]};head[a]=nume;}
bool vis[maxn];
int que[maxn];
long long dis[maxn];
void spfa(int st=1,int ed=n){
int top=0,end=0,now;
memset(dis,0x3f,sizeof dis);
memset(vis,0,sizeof vis);
que[end++]=st,dis[st]=0;
while(top!=end){
now=que[top++],top%=maxn;
vis[now]=false;
for(int i=head[now];i;i=e[i].next){
int to=e[i].to;
if(now==to) continue;
if(dis[now]+e[i].cost<dis[to]){
dis[to]=dis[now]+e[i].cost;
if(!vis[to]){
vis[to]=true;
if(dis[to]<dis[que[top]]){
top--;
if(top==-1)top=maxn-1;
que[top]=to;
}else{
que[end++]=to;
end%=maxn;
}
}
}
}
}
}
dijkstra,优先队列优化,链式前向星
typedef pair<int,int>p;
priority_queue<p> q;
int dis[maxn];
void dijkstra(){
int now;
memset(dis,0xc0,sizeof dis);
q.push(p(-INF,st)),tms[st]=1;
dis[st]=0,num[st]=nump[st];
while(!q.empty()){
now=q.top().second,q.pop();
for(int i=head[now];i;i=e[i].next){
int to=e[i].to;
if(now==to) continue;
int cost=dis[now]+e[i].cost;
if(cost<dis[to]){
dis[to]=cost;
q.push(p(-dis[to],to));
}
}
}
}
树状数组区间求和,单点更新
#define lb(x) (x&(-x))
int bt[maxn];
inline void upd(int pos,int x){while(pos<=n)bt[pos]+=x,pos+=lb(pos);}
inline int psum(int pos,int sum=0){while(pos) sum+=bt[pos],pos-=lb(pos);return sum;}
线段树单点更新区间求和
#define nd lst[now]
struct node {
int l,r,sum;
}lst[maxm];
void maketree(int s=1,int t=n,int now=1){
nd=(node){s,t,0};
if(s==t) return ;
maketree(s,(s+t)>>1,now<<1);
maketree(((s+t)>>1)+1,t,now<<1|1);
}
void update(int pos,int x,int now=1){
if(pos<nd.l||pos>nd.r) return ;
nd.sum+=x;
if(nd.r==nd.l) return;
update(pos,x,now<<1);
update(pos,x,now<<1|1);
}
int query(int s,int t,int now=1){
if(s>nd.r||t<nd.l) return 0;
if(s<=nd.l&&t>=nd.r) return nd.sum;
return query(s,t,now<<1)+query(s,t,now<<1|1);
}
线段树区间修改求和
#define nd seg[now]
#define ndl seg[now<<1]
#define ndr seg[now<<1|1]
using namespace std;
const int maxn=5e5+10;
int casn,n,m,k;
int num[maxn];
struct node {
int l,r;int sum,tag;
int len(){return r-l+1;}
}seg[maxn<<2];
void pushdown(int now){
if(nd.tag){
ndl.tag+=nd.tag;
ndr.tag+=nd.tag;
ndl.sum+=nd.tag*ndl.len();
ndr.sum+=nd.tag*ndr.len();
nd.tag=0;
}
}
void pushup(int now){nd.sum=ndl.sum+ndr.sum;}
void maketree(int s=1,int t=n,int now=1){
seg[now]=(node){s,t,num[s],0};
if(s==t)return ;
maketree(s,(s+t)>>1,now<<1);
maketree(((s+t)>>1)+1,t,now<<1|1);
pushup(now);
}
void update(int s,int t,ll x,int now=1){
if(s>nd.r||t<nd.l)return ;
if(s<=nd.l&&t>=nd.r){
nd.sum+=nd.len()*x,nd.tag+=x;
return ;
}
pushdown(now);
update(s,t,x,now<<1);
update(s,t,x,now<<1|1);
pushup(now);
}
int query(int s,int t,int now=1){
if(s>nd.r||t<nd.l) return 0;
if(s<=nd.l&&t>=nd.r) return nd.sum;
pushdown(now);
return query(s,t,now<<1)+query(s,t,now<<1|1);
}
手写二叉堆
void up(int now){
int t=hp[now];
while(now>1&&hp[now>>1]>hp[now])
hp[now]=hp[now>>1],now>>=1;
hp[now]=t;
}
void down(int now){
int t=hp[now];
for(int pos=now<<1;pos<=sz;pos<<=1){
pos+=(pos<sz)&&(hp[pos]>hp[pos+1]);
if(hp[pos]<t){
hp[now]=hp[pos];
now=pos;
}else break;
}
hp[now]=t;
}
inline void push(int x){hp[++sz]=x;up(sz);}
inline void pop(){swap(hp[1],hp[sz--]);down(1);}
inline int top(){return hp[1];}
kruskal
struct node{int from,to,cost;}e[maxm];
bool cmp(node &a,node &b){return a.cost<b.cost;}
void kruskal(){
sort(e,e+m,cmp);
for(int i=0;i<m;i++){
node t=e[i];
if(!same(t.from,t.to)){
unite(t.from,t.to);
}
}
}
//板子有锅是基本情况