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;
}
 posted on 2021-12-20 21:27  eleveni  阅读(54)  评论(0)    收藏  举报