2021.12.19 eleveni的刷题记录

2023-05-13,,

2021.12.19 eleveni的刷题记

0. 本次记录有意思的题

0.1 每个点恰好经过一次并且求最小时间

P2469 [SDOI2010]星际竞速

https://www.luogu.com.cn/problem/P2469

费用流

0.2 把数字序列转化为01串

AT2165 [AGC006D] Median Pyramid Hard

https://www.luogu.com.cn/problem/AT2165

二分

1. 基础算法

1.1 二分

https://www.luogu.com.cn/problem/AT2165

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#define IOS ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std; const int N=2e5+10;
int n,a[N]; inline int read(){
int s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')w=-1;
ch=getchar();
}
while(ch<='9'&&ch>='0'){
s=s*10+ch-'0';
ch=getchar();
}
return s*w;
}
inline bool check(int maxn){
for(int i=0;i<n-1;i++){
if((a[n-i]<=maxn&&a[n-i-1]<=maxn)||(a[n+i]<=maxn&&a[n+i+1]<=maxn))return true;
if((a[n-i]>maxn&&a[n-i-1]>maxn)||(a[n+i]>maxn&&a[n+i+1]>maxn))return false;
}
return a[1]<=maxn;
} signed main(){
IOS;
cin>>n;
for(int i=1;i<=n*2-1;i++)cin>>a[i];
int L=1,R=n*2-1,mid,ans;
while(L<R){
mid=(L+R)>>1;
if(check(mid))R=ans=mid;
else L=mid+1;
}
cout<<ans;
return 0;
}

https://www.luogu.com.cn/problem/P4343

记得把右边界开大!!!!

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<stack>
#include<cmath>
#include<queue>
#define ls (x)<<1
#define rs (x)<<1|1
#define IOS ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std; #define int long long
const int N=1e5+10;
int n,m,num[N]; inline int read(){
int s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')w=-1;
ch=getchar();
}
while(ch<='9'&&ch>='0'){
s=s*10+ch-'0';
ch=getchar();
}
return s*w;
}
inline bool check1(int maxn){
int now=0,cnt=0;
for(int i=1;i<=n;i++){
now+=num[i];
if(now<0)now=0;
if(now>=maxn)++cnt,now=0;
}
return cnt>=m;
}
inline bool check2(int maxn){
int now=0,cnt=0;
for(int i=1;i<=n;i++){
now+=num[i];
if(now<0)now=0;
if(now>=maxn)++cnt,now=0;
}
return cnt<=m;
} signed main(){
n=read();m=read();
int maxn=-1,minn=0x3f3f3f3f,R1=-1,R2=-1,L1=0,L2=0;
int tot=0;
for(int i=1;i<=n;i++){
num[i]=read();
tot+=num[i];
R1=max(R1,tot);R2=R1;
}
R1=R2=1e14;;
while(L1<=R1){
int mid=(L1+R1)>>1;
//cout<<L1<<" "<<R1<<" "<<mid<<endl;
if(check1(mid))maxn=mid,L1=mid+1;
else R1=mid-1;
}
//if(maxn==-1)return puts("-1"),0;
while(L2<=R2){
int mid=(L2+R2)>>1;
if(check2(mid))minn=mid,R2=mid-1;
else L2=mid+1;
}
//if(minn==0x3f3f3f3f)return puts("-1"),0;
if(maxn<minn)return puts("-1"),0;
cout<<max(minn,1*1ll)<<" "<<maxn;
return 0;
}

1.2 贪心

https://www.luogu.com.cn/problem/P4107

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<stack>
#include<cmath>
#include<queue>
#define ls (x)<<1
#define rs (x)<<1|1
#define IOS ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std; #define int long long
const int N=2e6+10;
int n,m,cnt,head[N],tmp[N],ans,val[N];
struct node{
int to,next;
}a[N]; inline int read(){
int s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')w=-1;
ch=getchar();
}
while(ch<='9'&&ch>='0'){
s=s*10+ch-'0';
ch=getchar();
}
return s*w;
}
inline void add(int u,int v){
++cnt;
a[cnt].to=v;
a[cnt].next=head[u];
head[u]=cnt;
}
inline int cmp(int x,int y){
return x<y;
}
inline void dfs(int x){
for(int i=head[x];i;i=a[i].next){
int v=a[i].to;
dfs(v);
}
int top=0;
for(int i=head[x];i;i=a[i].next){
int v=a[i].to;
tmp[++top]=val[v];
}
sort(tmp+1,tmp+top+1,cmp);
for(int i=1;i<=top;i++){
if(val[x]+tmp[i]-1<=m)val[x]+=tmp[i]-1,++ans;
else break;
}
} signed main(){
n=read();m=read();
for(int i=1;i<=n;i++)val[i]=read();
for(int i=1;i<=n;i++){
int tot=read();
val[i]+=tot;
for(int j=1;j<=tot;j++){
int x=read()+1;
add(i,x);
}
}
dfs(1);
cout<<ans;
return 0;
}

2. 计算几何

2.1 半平面交

如果不知道输入顺序,那么就顺时针逆时针都跑一遍求最大值

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std; const int N=1e5+10;
const double eps=1e-13;//!
int L,R; struct node{
double x,y;
inline node operator +(const node &b)const{
return (node){x+b.x,y+b.y};
}
inline node operator -(const node &b)const{
return (node){x-b.x,y-b.y};
}
}stain[N],Cross[N];
inline node operator *(node a,double k){
return (node){a.x*k,a.y*k};
}
inline node operator /(node a,double k){
return (node){a.x/k,a.y/k};
}
inline double cross(node x,node y){
return x.x*y.y-x.y*y.x;
}
inline double dot(node x,node y){
return x.x*y.x+x.y*y.y;
} struct nodei{
node pos,vec;
double angle;
inline void add(node a,node b){//
pos=a;vec=b;
angle=atan2(b.y,b.x);
}
bool operator <(const nodei &b){
return angle<b.angle;
}
}a[N],q[N];
inline int judge(nodei x,node y){
return cross(x.vec,y-x.pos)<=-eps;//判断点y是否在直线x右边
}
inline node findCross(nodei x,nodei y){
node z=x.pos-y.pos;
double t=cross(y.vec,z)/cross(x.vec,y.vec);
return x.pos+x.vec*t;
}
inline double calcArea(int n,node *a){// a:Cross ,求多边形面积
double fin=0.0;
for(int i=1;i<n;i++)fin+=cross(a[i],a[i+1]);
fin+=cross(a[n],a[1]);
fin/=2.0;
return fin;
}
inline int halfPlane(int n){
sort(a+1,a+n+1);
L=R=0;
q[0]=a[1];
for(int i=2;i<=n;i++){
while(L<R&&judge(a[i],Cross[R]))--R;
while(L<R&&judge(a[i],Cross[L+1]))++L;
q[++R]=a[i];
if(fabs(cross(q[R].vec,q[R-1].vec))<=eps){//第R条直线与第R-1条直线平行
if(judge(q[R],q[R-1].pos)&&dot(q[R].vec,q[R-1].vec)<=-eps)return 0;
--R;
if(!judge(q[R],a[i].pos))q[R]=a[i];//在左边
}
if(L<R)Cross[R]=findCross(q[R],q[R-1]);
}
while(L<R&&judge(q[L],Cross[R]))--R;
//cout<<"Case 2"<<endl;
if(R-L<=1)return 0;//左开右闭区间,当R-L<=1时就只有一条直线
Cross[L]=findCross(q[L],q[R]);
//cout<<"Case 1"<<endl;//
return 1;
} int main(){
int t,top=0;
//cin>>t;
//while(t--){
int n;cin>>n;
for(int i=n;i>=1;i--)cin>>stain[i].x>>stain[i].y;
for(int i=1;i<n;i++)a[++top].add(stain[i],stain[i%n+1]-stain[i]);
a[++top].add(stain[n],stain[1]-stain[n]);
//}
double maxn=0.0;
if(halfPlane(top))maxn=max(maxn,calcArea(R-L+1,Cross+L-1));
top=0;
for(int i=1;i<=n/2;i++)swap(stain[i],stain[n-i+1]);
for(int i=1;i<n;i++)a[++top].add(stain[i],stain[i+1]-stain[i]);
a[++top].add(stain[n],stain[1]-stain[n]);
if(halfPlane(top))maxn=max(maxn,calcArea(R-L+1,Cross+L-1));
printf("%.2lf",maxn);
return 0;
}

3. 图论

3.1 找规律

https://www.luogu.com.cn/problem/P2407

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#define IOS ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std; const int N=810;
int n,m,C[N][N],R[N][N];
char a[N][N]; int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
scanf("%s",a[i]+1);
int aim=0;
for(int j=1;j<=m;j++){
if(a[i][j]=='T')aim^=1;
R[i][j]=aim;
}
}
for(int j=1;j<=m;j++){
int aim=0;
for(int i=1;i<=n;i++){
if(a[i][j]=='T')aim^=1;
C[i][j]=aim;
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++)putchar('o'),putchar(R[i][j]?45:32);
cout<<endl;
if(i==n)break;
for(int j=1;j<=m;j++)putchar(C[i][j]?124:32),putchar(32);
cout<<endl;
}
return 0;
}

3.2 最短路

https://www.luogu.com.cn/problem/P4162

SLF优化SPFA

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
#include<cmath>
#define IOS ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std; const int N=35;
const int M=910;
const int inf=0x3f3f3f3f;
int n,m,T,cnt,head[M],start[M],vis[M],cnti[M],dis[M];
double ans,DIS[M][M];
char mapi[N][N];
struct node{
int to,next,val;
}a[M*8]; inline void add(int u,int v,int w){
++cnt;
a[cnt].to=v;
a[cnt].next=head[u];
a[cnt].val=w;
head[u]=cnt;
}
inline int id(int x,int y){
return (x-1)*m+y;
}
inline void spfa(int s){
deque<int>q;
for(int i=1;i<=n*m;i++)dis[i]=inf,vis[i]=0;
if(start[s])dis[s]=1;else dis[s]=0;
vis[s]=1;
q.push_back(s);
while(!q.empty()){
int x=q.front();q.pop_front();
if(dis[x]<=T)ans=max(ans,DIS[s][x]);
vis[x]=0;
for(int i=head[x];i;i=a[i].next){
int v=a[i].to;
if(dis[v]>dis[x]+a[i].val){
dis[v]=dis[x]+a[i].val;
if(!vis[v]){
vis[v]=1;
if(dis[v]<dis[q.front()])q.push_front(v);
else q.push_back(v);
}
}
}
}
//cout<<"start "<<s<<endl;
//for(int i=1;i<=n*m;i++)cout<<dis[i]<<" ";cout<<endl;
} int main(){
cin>>n>>m>>T;
for(int i=1;i<=n;i++){
scanf("%s",mapi[i]+1);
for(int j=1;j<=m;j++){
int x=id(i,j);
if(mapi[i][j]=='1')start[x]=1;
}
}
for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)
for(int k=1;k<=n;k++)for(int l=1;l<=m;l++){
int id1=id(i,j),id2=id(k,l);
DIS[id1][id2]=DIS[id2][id1]=(double)sqrt((double)(i-k)*(i-k)+double(j-l)*(j-l));
}
/*cout<<"DIS "<<endl;
for(int i=1;i<=n*m;i++){
for(int j=1;j<=n*m;j++)cout<<DIS[i][j]<<" ";
cout<<endl;
}
cout<<endl;*/
for(int i=1;i<=n;i++)for(int j=1;j<=m;j++){
int idi=id(i,j);
if(i<n)add(idi,idi+m,start[idi+m]),add(idi+m,idi,start[idi]);
if(j<m)add(idi,idi+1,start[idi+1]),add(idi+1,idi,start[idi]);
}
for(int i=1;i<=n*m;i++)spfa(i);
printf("%.6lf",ans);
return 0;
}

3.3 Tarjan

https://www.luogu.com.cn/problem/P2469

60pts:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<stack>
#include<cmath>
#define ls (x)<<1
#define rs (x)<<1|1
#define IOS ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std; const int N=4e4+10;
const int M=2e5+10;
const int K=6e4+10;
int n,m,cnt,head[N],cnti,headi[N],ans;
int ind,dfn[N],low[N],belong[N],vis[N];
int dfsx,true_id[N],id_true[N],dep[N],top[N],son[N],sizei[N],fa[N];
int val[N<<4],lazy[N<<4];
struct Query{
int op,u,v,ans;
}queryi[K];
struct node{
int to,next,flag;
}a[M],ai[M];
stack<int>s; inline int read(){
int s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')w=-1;
ch=getchar();
}
while(ch<='9'&&ch>='0'){
s=s*10+ch-'0';
ch=getchar();
}
return s*w;
}
inline void add(int u,int v){
++cnt;
a[cnt].to=v;
a[cnt].next=head[u];
head[u]=cnt;
}
inline void addi(int u,int v){
++cnti;
ai[cnti].to=v;
ai[cnti].next=headi[u];
headi[u]=cnti;
}
inline void Tarjan(int x,int fai){
dfn[x]=low[x]=++ind;
s.push(x);
for(int i=head[x];i;i=a[i].next){
if(a[i].flag==1)continue;
int v=a[i].to;
if(!dfn[v])Tarjan(v,x),low[x]=min(low[x],low[v]);
else if(dfn[v]<dfn[x]&&v!=fai)low[x]=min(low[x],dfn[v]);
}
int k=0;
if(low[x]==dfn[x]){
do{
k=s.top();s.pop();
belong[k]=x;
vis[k]=0;
}while(k!=x);
}
}
inline void build(int x,int l,int r){
if(l==r)return (void)(val[x]=1);
int mid=(l+r)>>1;
build(ls,l,mid);
build(rs,mid+1,r);
val[x]=val[ls]+val[rs];
}
inline void pushdown(int x){
if(!lazy[x])return ;
lazy[ls]=lazy[rs]=lazy[x];
val[ls]=val[rs]=0;
lazy[x]=0;
}
inline void change(int x,int l,int r,int L,int R){
if(L>r||R<l)return ;
if(l>=L&&r<=R)return (void)(val[x]=0,lazy[x]=1);
pushdown(x);
int mid=(l+r)>>1;
if(L<=mid)change(ls,l,mid,L,R);
if(R>mid)change(rs,mid+1,r,L,R);
val[x]=val[ls]+val[rs];
}
inline int query(int x,int l,int r,int L,int R){
if(L>r||R<l)return 0;
if(l>=L&&r<=R)return val[x];
pushdown(x);
int mid=(l+r)>>1;
int ans=0;
if(L<=mid)ans+=query(ls,l,mid,L,R);
if(R>mid)ans+=query(rs,mid+1,r,L,R);
val[x]=val[ls]+val[rs];
return ans;
}
inline void dfs1(int x,int fai){
sizei[x]=1;fa[x]=fai;dep[x]=dep[fai]+1;
for(int i=headi[x];i;i=ai[i].next){
int v=ai[i].to;
if(v==fai)continue;
dfs1(v,x);
sizei[x]+=sizei[v];
if(sizei[v]>sizei[son[x]])son[x]=v;
}
}
inline void dfs2(int x,int topi){
top[x]=topi;
true_id[x]=++dfsx;id_true[dfsx]=x;
if(son[x]&&!true_id[son[x]])dfs2(son[x],topi);
for(int i=headi[x];i;i=ai[i].next){
int v=ai[i].to;
if(true_id[v])continue;
if(v==fa[x]||v==son[x])continue;
dfs2(v,v);
}
}
inline void changeline(int x,int y,int flag){
//cout<<x<<" "<<y<<" "<<top[x]<<" "<<top[y]<<endl;
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])swap(x,y);
if(flag)ans+=query(1,1,dfsx,true_id[top[x]],true_id[x]);
else change(1,1,dfsx,true_id[top[x]],true_id[x]);
x=fa[top[x]];
//cout<<x<<" "<<y<<" "<<top[x]<<" "<<top[y]<<endl;
}
if(dep[x]>dep[y])swap(x,y);
if(flag)ans+=query(1,1,dfsx,true_id[x]+1,true_id[y]);
else change(1,1,dfsx,true_id[x]+1,true_id[y]);
//cout<<x<<" "<<y<<endl;//
}
inline void find(){
for(int i=1;i<=20;i++)cout<<val[i]<<" ";
cout<<endl;
} int main(){
n=read();m=read();
for(int i=1;i<=m;i++){
int u,v;
u=read();v=read();
add(u,v);add(v,u);
}
int tot=0;
for(int i=1;i;i++){
queryi[i].op=read();
if(queryi[i].op==-1){
tot=i-1;
break;
}
queryi[i].u=read();queryi[i].v=read();
if(queryi[i].op==0){
for(int j=head[queryi[i].u];j;j=a[j].next){
if(a[j].flag==1)continue;
int v=a[j].to;
if(v==queryi[i].v){
a[j].flag=1;
break;
}
}
for(int j=head[queryi[i].v];j;j=a[j].next){
if(a[j].flag==1)continue;
int v=a[j].to;
if(v==queryi[i].u){
a[j].flag=1;
break;
}
}
}
}
for(int i=1;i<=n;i++)if(!dfn[i])Tarjan(i,i);
/*cout<<"belong "<<endl;
for(int i=1;i<=n;i++)cout<<belong[i]<<" ";cout<<endl;
cout<<"addi "<<endl;*/
for(int i=1;i<=n;i++)
for(int j=head[i];j;j=a[j].next){
if(a[j].flag)continue;
int v=a[j].to;
if(belong[i]!=belong[v]){
int from=belong[i],to=belong[v];
addi(from,to);addi(to,from);
//cout<<from<<" "<<to<<endl;
}
}
//cout<<"start "<<ai[1].to<<endl;
dfs1(ai[1].to,ai[1].to);dfs2(ai[1].to,ai[1].to);
/*cout<<"dfsx "<<endl;
for(int i=1;i<=dfsx;i++)cout<<i<<" "<<id_true[i]<<endl;
cout<<"son "<<endl;
for(int i=1;i<=n;i++)cout<<son[i]<<" ";cout<<endl;
cout<<"top "<<endl;
for(int i=1;i<=n;i++)cout<<top[i]<<" ";cout<<endl;*/
build(1,1,dfsx);
//cout<<"queryi "<<endl;
for(int i=tot;i>=1;i--){
ans=0;
int ui=belong[queryi[i].u],vi=belong[queryi[i].v];
//cout<<queryi[i].op<<" "<<ui<<" "<<vi<<" "<<endl;
changeline(ui,vi,queryi[i].op);
queryi[i].ans=ans;
//find();
}
for(int i=1;i<=tot;i++)if(queryi[i].op==1)cout<<queryi[i].ans<<endl;
return 0;
}

别人100pts:

#include<map>
#include<stack>
#include<cstdio>
#include<algorithm>
using namespace std;
template<class type>inline const void read(type &in)
{
in=0;char ch=getchar();short fh=1;
while (ch<48||ch>57)fh=ch=='-'?-1:fh,ch=getchar();
while (ch>47&&ch<58)in=(in<<3)+(in<<1)+ch-48,ch=getchar();
in*=fh;
}
const int N=3e4+10,M=1e5+10,Q=4e4+10;
int n,m,a[M],b[M];
stack<int>ans;
map<pair<int,int>,int>e;
struct question{int u,v,type;}q[Q]; //存储每个询问信息
class Edge
{
private:
int cnt;
public:
int head[N],to[M<<1],next[M<<1];
inline const void addedge(int u,int v)
{
next[++cnt]=head[u];
head[u]=cnt;
to[cnt]=v;
}
inline const void connect(int u,int v)
{
addedge(u,v);
addedge(v,u);
}
}g,t;
class Double_Connected_Component //边双处理
{
private:
stack<int>s;
int dfn[N],low[N],cnt;
public:
int dcc[N],tot;
protected:
inline const void tarjan(int u,int fa)
{
dfn[u]=low[u]=++cnt;s.push(u);int v;
for (int i=g.head[u];i;i=g.next[i])
if ((v=g.to[i])!=fa)
if (!dfn[v])tarjan(v,u),low[u]=min(low[u],low[v]);
else if (!dcc[v])low[u]=min(low[u],dfn[v]);
if (low[u]!=dfn[u])return;tot++;
do v=s.top(),s.pop(),dcc[v]=tot;while (u!=v);
}
public:
inline const void tarjan()
{
for (int i=1;i<=n;i++)
if (!dfn[i])
tarjan(i,0);
}
inline const void rebuild() //缩点成树
{
for (int i=1;i<=n;i++)
for (int u,v,j=g.head[i];j;j=g.next[j])
if ((u=dcc[i])!=(v=dcc[g.to[j]]))
t.addedge(u,v);
}
}dcc;
class Segment_Tree //线段树(指针)
{
private:
struct tree
{
int sum;
bool tag;
tree *lson,*rson;
inline const void pushup()
{
sum=lson->sum+rson->sum;
}
inline const void cover()
{
tag=1;sum=0;
}
inline const void pushdown()
{
if (!tag)return;
lson->cover();
rson->cover();
tag=0;
}
inline const void update(int l,int r,int L,int R)
{
if (l>R||r<L)return;
if (l>=L&&r<=R)return cover();
pushdown();
int mid=l+r>>1;
lson->update(l,mid,L,R);
rson->update(mid+1,r,L,R);
pushup();
}
inline const int query(int l,int r,int L,int R)
{
if (l>R||r<L)return 0;
if (l>=L&&r<=R)return sum;
pushdown();
int mid=l+r>>1;
return lson->query(l,mid,L,R)+rson->query(mid+1,r,L,R);
}
}memory_pool[N<<2],*tail;
inline const void init()
{
tail=memory_pool;
}
inline tree *spawn()
{
tree *p=tail++;
p->tag=p->sum=0;
p->lson=p->rson=NULL;
return p;
}
public:
tree *root;
inline Segment_Tree(){init();}
inline const void build(tree *&p,int l,int r)
{
p=spawn();
if (l==r)return (void)(p->sum=(l!=1)); //边权转点权,1号点(根节点)上面没有边,权值为0
int mid=l+r>>1;
build(p->lson,l,mid);
build(p->rson,mid+1,r);
p->pushup();
}
}sgt;
class Heavy_Light_Decomposition //树剖
{
private:
int size[N],top[N],fa[N],dep[N],dfn[N],wson[N],cnt;
public:
inline const void dfs(int p)
{
size[p]=1;
for (int i=t.head[p];i;i=t.next[i])
{
int son=t.to[i];
if (son==fa[p])continue;
fa[son]=p;dep[son]=dep[p]+1;
dfs(son);size[p]+=size[son];
if (size[son]>size[wson[p]])wson[p]=son;
}
}
inline const void dfs(int p,int tp)
{
top[p]=tp;dfn[p]=++cnt;
if (wson[p])dfs(wson[p],tp);
for (int son,i=t.head[p];i;i=t.next[i])
if (!dfn[son=t.to[i]])
dfs(son,son);
}
inline const void update(int a,int b)
{
while (top[a]^top[b])
{
if (dep[top[a]]<dep[top[b]])swap(a,b);
sgt.root->update(1,dcc.tot,dfn[top[a]],dfn[a]);
a=fa[top[a]];
}
if (dep[a]>dep[b])swap(a,b);
sgt.root->update(1,dcc.tot,dfn[a]+1,dfn[b]);
}
inline const int query(int a,int b)
{
int ans=0;
while (top[a]^top[b])
{
if (dep[top[a]]<dep[top[b]])swap(a,b);
ans+=sgt.root->query(1,dcc.tot,dfn[top[a]],dfn[a]);
a=fa[top[a]];
}
if (dep[a]>dep[b])swap(a,b);
return ans+sgt.root->query(1,dcc.tot,dfn[a]+1,dfn[b]);
}
}hld;
int main()
{
read(n);read(m);
for (int i=1;i<=m;i++)read(a[i]),read(b[i]);
int qtot;
for (qtot=1;read(q[qtot].type),~q[qtot].type;qtot++)
{
read(q[qtot].u);read(q[qtot].v);
if (q[qtot].type)continue;
e[make_pair(q[qtot].u,q[qtot].v)]++;
e[make_pair(q[qtot].v,q[qtot].u)]++; //无向图,反过来的也要更改
}
for (int i=1;i<=m;i++)
if (e.find(make_pair(a[i],b[i]))!=e.end()&&e[make_pair(a[i],b[i])])
e[make_pair(a[i],b[i])]--,e[make_pair(b[i],a[i])]--;
else g.connect(a[i],b[i]);
dcc.tarjan();dcc.rebuild();
hld.dfs(1);hld.dfs(1,1);
sgt.build(sgt.root,1,dcc.tot);
for (int i=qtot-1;i;i--)
if (q[i].type)ans.push(hld.query(dcc.dcc[q[i].u],dcc.dcc[q[i].v])); //由于是倒序处理,所以输出也要倒过来,因为tarjan缩点的时候会用到栈,干脆也用栈来实现倒序好了
else hld.update(dcc.dcc[q[i].u],dcc.dcc[q[i].v]);
while (ans.size())printf("%d\n",ans.top()),ans.pop();
return 0;
}

3.4 网络流

3.4.1 费用流

https://www.luogu.com.cn/problem/P2469

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<stack>
#include<cmath>
#include<queue>
#define ls (x)<<1
#define rs (x)<<1|1
#define IOS ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std; const int N=160010;
const int inf=0x3f3f3f3f;
int n,m,start,endi,cnt=1,head[N];
int maxnflow,maxncost,vis[N],flow[N],pre[N],dis[N];
struct node{
int to,next,val,cost;
}a[N*3]; inline int read(){
int s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')w=-1;
ch=getchar();
}
while(ch<='9'&&ch>='0'){
s=s*10+ch-'0';
ch=getchar();
}
return s*w;
}
inline void addi(int u,int v,int w,int x){
++cnt;
a[cnt].to=v;
a[cnt].val=w;
a[cnt].cost=x;
a[cnt].next=head[u];
head[u]=cnt;
}
inline void add(int u,int v,int w,int x){
addi(u,v,w,x);addi(v,u,0,-x);
}
inline int spfa(int s,int t){
memset(dis,inf,sizeof(dis));
memset(vis,0,sizeof(vis));
queue<int>q;
dis[s]=0;flow[s]=inf;vis[s]=1;
q.push(s);
while(!q.empty()){
int x=q.front();q.pop();
vis[x]=0;
for(int i=head[x];i;i=a[i].next){
int v=a[i].to;
if(dis[v]>dis[x]+a[i].cost&&a[i].val){
dis[v]=dis[x]+a[i].cost;
flow[v]=min(flow[x],a[i].val);
pre[v]=i;
if(!vis[x])vis[v]=1,q.push(v);
}
}
}
return dis[t]!=inf;
}
inline void update(int s,int t){
int x=t;
while(x!=s){
int xi=pre[x];
a[xi].val-=flow[t];
a[xi^1].val+=flow[t];
x=a[xi^1].to;
}
maxnflow+=flow[t];
maxncost+=flow[t]*dis[t];
}
inline void EK(int s,int t){
while(spfa(s,t))update(s,t);
} int main(){
n=read();m=read();
start=n*2+1,endi=n*2+2;
for(int i=1;i<=n;i++){
int x=read();
add(start,i,1,0);
add(start,i+n,1,x);
add(i+n,endi,1,0);
}
for(int i=1;i<=m;i++){
int u,v,w;
u=read();v=read();w=read();
if(u>v)swap(u,v);
add(u,v+n,1,w);
}
EK(start,endi);
cout<<maxncost;
return 0;
}

4. 数学

4.1 矩阵加速

https://www.luogu.com.cn/problem/P2461

呵呵,输出必须是非负整数!!

20pts:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<stack>
#include<cmath>
#include<queue>
#define ls (x)<<1
#define rs (x)<<1|1
#define IOS ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std; #define int long long
const int N=20;
int n,m,K,mod;
struct Matrix{
int num[N][N];
Matrix(){
memset(num,0,sizeof(num));
}
inline Matrix operator *(const Matrix &b)const{
Matrix c;
for(int i=1;i<=K;i++)
for(int j=1;j<=K;j++)
for(int k=1;k<=K;k++)
c.num[i][j]=(c.num[i][j]+num[i][k]*b.num[k][j]%mod)%mod;
return c;
}
}ans,basic; inline int read(){
int s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')w=-1;
ch=getchar();
}
while(ch<='9'&&ch>='0'){
s=s*10+ch-'0';
ch=getchar();
}
return s*w;
}
inline Matrix operator ^(Matrix x,int y){
Matrix fin=x;--y;
while(y){
if(y&1)fin=fin*x;
x=x*x;
y>>=1;
}
return fin;
} signed main(){
K=read();
for(int i=1;i<=K;i++)ans.num[i][1]=read();
for(int i=K;i>=1;i--){
if(i<K)basic.num[i][i+1]=1;
basic.num[K][i]=read();
}
//for(int i=1;i<=K;i++)cout<<basic.num[K][i]<<" ";cout<<endl;
/*cout<<"ans "<<endl;
for(int i=1;i<=K;i++)cout<<ans.num[i][1]<<endl;
cout<<"basic "<<endl;
for(int i=1;i<=K;i++){
for(int j=1;j<=K;j++)cout<<basic.num[i][j]<<" ";
cout<<endl;
}
cout<<endl;*/
m=read();n=read();mod=read();
if(m-K>0)ans=(basic^(m-K))*ans;
//cout<<"ans "<<endl;
//for(int i=1;i<=K;i++)cout<<ans.num[i][1]<<endl;
int tot=ans.num[K][1];
for(int i=1;i<=(n-m)%K;i++)ans=basic*ans,tot=(tot+ans.num[K][1])%mod;
basic=basic^K;
for(int i=1;i<=(n-m)/K;i++){
ans=basic*ans;
for(int j=1;j<=K;j++)tot=(tot+ans.num[j][1])%mod;
}
cout<<tot;
return 0;
}

100pts:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<stack>
#include<cmath>
#include<queue>
#define ls (x)<<1
#define rs (x)<<1|1
#define IOS ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std; #define int long long
const int N=20;
int n,m,K,mod,sum[N];
struct Matrix{
int num[N][N];
Matrix(){
memset(num,0,sizeof(num));
}
inline Matrix operator *(const Matrix &b)const{
Matrix c;
for(int i=1;i<=K+1;i++)
for(int j=1;j<=K+1;j++)
for(int k=1;k<=K+1;k++)
c.num[i][j]=(c.num[i][j]+num[i][k]*b.num[k][j]%mod)%mod;
return c;
}
}ans,basic; inline int read(){
int s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')w=-1;
ch=getchar();
}
while(ch<='9'&&ch>='0'){
s=s*10+ch-'0';
ch=getchar();
}
return s*w;
}
inline Matrix operator ^(Matrix x,int y){
Matrix fin;
if(y==0)return fin;
fin=x;--y;
while(y>0){
if(y&1)fin=fin*x;
x=x*x;
y>>=1;
}
return fin;
} signed main(){
K=read();
for(int i=1;i<=K;i++)ans.num[i][1]=read();
for(int i=K;i>=1;i--){
if(i<K)basic.num[i][i+1]=1;
basic.num[K+1][i]=basic.num[K][i]=read();
}
basic.num[K+1][K+1]=1;
m=read();n=read();mod=read();
for(int i=1;i<=K;i++)
sum[i]=(sum[i-1]+(ans.num[i][1]%=mod))%mod,
basic.num[K][i]%=mod,basic.num[K+1][i]%=mod;
ans.num[K+1][1]=sum[K];
int tot1=0,tot2=0;
if(m<=K+1)tot1=sum[m-1];
else tot1=((basic^(m-1-K))*ans).num[K+1][1];
if(n<=K)tot2=sum[n];
else tot2=((basic^(n-K))*ans).num[K+1][1];
//cout<<tot1<<" "<<tot2<<endl;
cout<<((tot2-tot1)%mod+mod)%mod;
return 0;
}

5. 动态规划

5.1 贪心优化

https://www.luogu.com.cn/problem/P2577

这个看似可以记忆化搜索。

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<stack>
#include<cmath>
#include<queue>
#define ls (x)<<1
#define rs (x)<<1|1
#define IOS ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std; const int N=210;
const int inf=0x3f3f3f3f;
int n,f[N][N*N],sum[N];
struct node{
int wait,eat;
bool operator <(const node &b)const{
return eat>b.eat;
}
}a[N]; inline int read(){
int s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')w=-1;
ch=getchar();
}
while(ch<='9'&&ch>='0'){
s=s*10+ch-'0';
ch=getchar();
}
return s*w;
} int main(){
n=read();
for(int i=1;i<=n;i++)a[i].wait=read(),a[i].eat=read();
sort(a+1,a+n+1);
for(int i=1;i<=n;i++)sum[i]=sum[i-1]+a[i].wait;
memset(f,inf,sizeof(f));
f[0][0]=0;
for(int i=1;i<=n;i++)
for(int j=0;j<=sum[i];j++){
if(j>=a[i].wait)f[i][j]=min(f[i][j],max(f[i-1][j-a[i].wait],j+a[i].eat));
f[i][j]=min(f[i][j],max(f[i-1][j],sum[i]-j+a[i].eat));
}
int ans=inf;
for(int i=0;i<=sum[n];i++)ans=min(ans,f[n][i]);
cout<<ans;
return 0;
}

2021.12.19 eleveni的刷题记录的相关教程结束。

《2021.12.19 eleveni的刷题记录.doc》

下载本文的Word格式文档,以方便收藏与打印。