• 20201017 模拟赛总结


    题目PDF,提取码 q2xb

    T1

    原题:洛谷 P4198

    线段树。每个节点维护这个区间的答案 (mathrm{ans}) 和最大值 (max),对于查询操作,答案显然为根节点的 (mathrm{ans})。对于修改操作,合并两个子区间较为麻烦。
    首先,左儿子的 (mathrm{ans}) 肯定在其父亲的 (mathrm{ans}) 中,直接累加即可;对于右儿子,要找到其答案序列中大于等于左儿子的 (max) 的第一个值 (x),并考虑这个值能给答案做多大贡献。具体地,右儿子做的贡献就是右儿子的答案序列中 (x)(x) 后面的元素的数量。写一个函数,在线段树上二分即可。

    时间复杂度 (mathcal O(nlog^2 n))

    #include<iostream>
    #include<cstdio> 
    #include<algorithm>
    #include<cstring>
    using namespace std;
    const int N=1e5;
    struct seg
    {
    	int l,r,ans;
    	double max;
    } t[N*4+10];
    #define ls (p*2)
    #define rs (p*2+1)
    void build(int p,int l,int r)
    {
    	t[p].l=l; t[p].r=r;
    	if(l==r)
    	{
    		t[p].ans=0; t[p].max=0;
    		return;
    	} 
    	int mid=(l+r)/2;
    	build(ls,l,mid);
    	build(rs,mid+1,r);
    	t[p].ans=0;t[p].max=0;
    }
    int get(int p,double k)
    {
    	if(t[p].l==t[p].r) return t[p].max>k;
    	if(t[ls].max>k) return get(ls,k)+t[p].ans-t[ls].ans;
    	if(t[ls].max<=k && t[rs].max>k) return get(rs,k);
    	return 0;
    }
    void modify(int p,int l,double d)
    {
    	if(t[p].l==t[p].r) 
    	{
    		t[p].max=d;
    		t[p].ans=1;
    //		printf("t[%d].ans:%d   .max:%.3lf
    ",p,t[p].ans,t[p].max);
    		return;
    	}
    	int mid=(t[p].l+t[p].r)/2;
    	if(l<=mid) modify(ls,l,d);
    	else modify(rs,l,d);
    //	printf("t[%d.ls].max:%.3lf
    ",p,t[ls].max);
    //	printf("t[%d.rs].max:%.3lf
    ",p,t[rs].max); 
    	t[p].ans=t[ls].ans+get(rs,t[ls].max);
    //	printf("get(%d, %.3lf): %d
    ",rs,t[ls].max,get(rs,t[ls].max));
    	t[p].max=max(t[ls].max,t[rs].max);
    }
    inline void read(int &x)
    {
    	x=0; int f=1;
    	char c=getchar();
    	while(c<'0' || c>'9')
    	{
    		if(c=='-') f=-1;
    		c=getchar();
    	}
    	while(c>='0' && c<='9')
    	{
    		x=(x<<1)+(x<<3)+(c^48);
    		c=getchar();
    	}
    	x*=f;
    }
    int main()
    {
    	int n,m;
    	read(n);read(m);
    	build(1,1,n);
    	for(int i=1;i<=m;i++)
    	{
    		int x,y;
    		read(x);read(y);
    		modify(1,x,y/1.0/x);
    		printf("%d
    ",t[1].ans);
    //		puts("---------");
    	}
    	return 0;
    }
    

    T2

    原题:洛谷 P1266

    (operatorname{dis}(u,s)) 代表以速度 (s) 到达点 (u) 的最短时间,这样在最短路的过程中就可以处理 (V_i)(0) 的情况。SPFA 求最短路即可。

    时间复杂度 (mathcal O( ext{懒得算})=mathcal O( ext{能过}))

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<queue>
    using namespace std;
    const int N=150,M=150*150,V=500;
    int head[N+10],ver[M+10],nxt[M+10],v[M+10],l[M+10],tot=0;
    inline void add(int x,int y,int vv,int ll)
    {
    	ver[++tot]=y;
    	v[tot]=vv;
    	l[tot]=ll;
    	nxt[tot]=head[x];
    	head[x]=tot; 
    }
    double dis[N+10][V+10];
    bool book[N+10][V+10]; 
    typedef pair<int,int> pii;
    #define mp make_pair
    pii pre[N+10][V+10];
    int ans[N+10],cnt=0;
    inline void spfa()
    {
    	queue<pii> que;
    	que.push(mp(1,70));//first:vertex  second:speed
    	book[1][70]=1;
    	pre[1][70]=mp(-1,-1);
    //	memset(dis,0x3f,sizeof(dis));
    //	printf("dis[0][0]:%.3lf
    ",dis[0][0]);
    	for(int i=1;i<=N;i++)
    		for(int j=1;j<=V;j++)
    			dis[i][j]=(double)0x7fffffff;
    	dis[1][70]=0;
    	while(!que.empty())
    	{
    		pii x=que.front(); que.pop();
    //		printf("x:%d
    ",x.first);
    		book[x.first][x.second]=0;
    		for(int i=head[x.first];i;i=nxt[i])
    		{
    			int y=ver[i],vv=v[i],ll=l[i];
    			if(!vv)
    			{
    //				printf("y:%d
    ",y);
    				if(dis[x.first][x.second]+(double)(ll/1.0/x.second)<dis[y][x.second])
    				{
    					dis[y][x.second]=dis[x.first][x.second]+(double)(ll/1.0/x.second);
    					if(!book[y][x.second])
    					{
    						book[y][x.second]=1;
    						que.push(mp(y,x.second));
    					}
    					pre[y][x.second]=x;
    				}
    			}
    			else
    			{
    				if(dis[x.first][x.second]+(double)(ll/1.0/vv)<dis[y][vv])
    				{
    					dis[y][vv]=dis[x.first][x.second]+(double)(ll/1.0/vv);
    					if(!book[y][vv])
    					{
    						book[y][vv]=1;
    						que.push(mp(y,vv));
    					}
    					pre[y][vv]=x;
    				}
    			}
    		}
    	}
    }
    inline void read(int &x)
    {
    	x=0; int f=1;
    	char c=getchar();
    	while(c<'0' || c>'9')
    	{
    		if(c=='-') f=-1;
    		c=getchar();
    	}
    	while(c>='0' && c<='9')
    	{
    		x=(x<<1)+(x<<3)+(c^48);
    		c=getchar();
    	}
    	x*=f;
    }
    void output(int x,int y)
    {
    //	printf("%d ",x);
    	ans[++cnt]=x-1;
    	if(pre[x][y].first==-1) return;
    	output(pre[x][y].first,pre[x][y].second); 
    }
    int main()
    {
    	int n,m,d;
    	read(n);read(m);read(d);d++;
    	for(int i=1;i<=m;i++)
    	{
    		int x,y,vv,ll;
    		read(x);read(y);read(vv);read(ll);
    		x++;y++;
    		add(x,y,vv,ll);
    	}
    	double Min=(double)0x7fffffff;
    	spfa();
    	int f;
    	for(int i=1;i<=500;i++)
    	{
    		if(dis[d][i]<Min)
    		{
    			Min=dis[d][i];
    			f=i;
    		}
    	}
    	output(d,f);
    	for(int i=cnt;i;i--) printf("%d ",ans[i]);
    //	printf("%.3lf %d",Min,f);
    }
    

    T3

    原题:bzoj 3257

    (f(x,0/1/2)) 表示根节点为 (x),状态分别为 (0/1/2) 的最小代价,其中状态 (1) 表示没有黑色节点,状态 (2) 表示没有白色节点,状态 (3) 表示有一个白色节点,然后暴力转移。最后的答案就是 (minleft(f(1,0),f(1,1),f(1,2) ight))

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    #define int long long
    const int N=1e6,M=2e6,INF=0x3f3f3f3f3f3f3f3f;
    int black[N+10],white[N+10],col[N+10];
    int head[N+10],ver[M+10],nxt[M+10],tot,son[N+10],edge[M+10]; 
    inline void add(int x,int y,int z)
    {
    	ver[++tot]=y;
    	edge[tot]=z;
    	nxt[tot]=head[x];
    	head[x]=tot;
    }
    inline void read(int &x)
    {
    	x=0;
    	int f=1;
    	char c=getchar();
    	while(c<'0' || c>'9')
    	{
    		if(c=='-') f=-1;
    		c=getchar();
    	}
    	while(c>='0' && c<='9')
    	{
    		x=(x<<1)+(x<<3)+(c^48);
    		c=getchar();
    	}
    	x*=f;
    }
    int sum[N+10];
    int fa[N+10];
    void dfs(int u)
    {
    	for(int i=head[u];i;i=nxt[i])
    	{
    		int v=ver[i];
    		if(fa[u]==v) continue;
    		son[u]++;
    		fa[v]=u;
    		dfs(v);
    //		black[u]=black[v]+(col[u]==0);
    //		white[u]=white[v]+(col[v]==1);
    	}
    }
    int f[N+10][3]; // 0:0black  1:0white  2:1whit
    void dp(int u)
    {
    	if(!son[u])
    	{
    		if(col[u]==0) f[u][1]=0;
    		else if(col[u]==1) f[u][0]=f[u][2]=0;
    		else f[u][0]=f[u][1]=0;
    		return;
    	}
    	if(col[u]==0)
    	{
    		f[u][0]=INF;f[u][1]=0;
    		for(int i=head[u];i;i=nxt[i])
    		{
    			int v=ver[i],w=edge[i];
    			if(v==fa[u]) continue;
    			dp(v);
    			f[u][1]+=min(f[v][1],min(f[v][0],f[v][2])+w);
    			sum[u]+=min(f[v][1],min(f[v][0],f[v][2])+w);
    		}
    		for(int i=head[u];i;i=nxt[i])
    		{
    			int v=ver[i],w=edge[i];
    			if(v==fa[u]) continue;
    			f[u][2]=min(f[u][2],(sum[u]-min(f[v][1],min(f[v][0],f[v][2])+w))+f[v][2]);
    		}
    	}
    	else if(col[u]==1)
    	{
    		f[u][0]=0;f[u][1]=INF ;f[u][2]=0;
    		for(int i=head[u];i;i=nxt[i])
    		{
    			int v=ver[i],w=edge[i];
    			if(v==fa[u]) continue;
    			dp(v);
    			f[u][0]+=min(f[v][0],min(f[v][1],f[v][2])+w);
    			f[u][2]+=min(f[v][1],min(f[v][0],f[v][2])+w);
    		}
    	}
    	else
    	{
    		f[u][0]=0;f[u][1]=0;
    		for(int i=head[u];i;i=nxt[i])
    		{
    			int v=ver[i],w=edge[i];
    			if(v==fa[u]) continue;
    			dp(v);
    			f[u][0]+=min(f[v][0],min(f[v][1],f[v][2])+w);
    			f[u][1]+=min(f[v][1],min(f[v][0],f[v][2])+w);
    			sum[u]+=min(f[v][1],min(f[v][0],f[v][2])+w);
    		}
    		for(int i=head[u];i;i=nxt[i])
    		{
    			int v=ver[i],w=edge[i];
    			if(v==fa[u]) continue;
    			f[u][2]=min(f[u][2],f[v][2]+(sum[u]-min(f[v][1],min(f[v][0],f[v][2])+w)));
    		}
    	}
    }//0black    1white
    void sol()
    {
    	memset(head,0,sizeof(head));tot=0;	
    	int n;
    	scanf("%lld",&n);
    	for(int i=1;i<=n;i++) scanf("%lld",&col[i]);
    	for(int i=1;i<n;i++)
    	{
    		int u,v,w;
    		scanf("%lld %lld %lld",&u,&v,&w);
    		add(u,v,w);
    		add(v,u,w);
    	}
    	memset(sum,0,sizeof(sum));
    	memset(son,0,sizeof(son)); 
    	memset(f,0x3f,sizeof(f));
    	memset(fa,-1,sizeof(fa));
    	dfs(1);
    	dp(1);
    //	for(int i=1;i<=n;i++)
    //		for(int j=0;j<3;j++)
    //			printf("f[%d][%d]: %d
    ",i,j,f[i][j]);
    	printf("%lld
    ",min(f[1][1],min(f[1][0],f[1][2])));
    }
    signed main()
    {
    	int T;
    	scanf("%lld",&T);
    	while(T--) sol();
    	return 0;
    }
    
  • 相关阅读:
    20150128-堆雪人
    20150127-梦里笑醒的声音
    20150126-渡口
    20150125-阴天
    FastAdmin 的上传代码在哪里?
    在 Linux 安装 IIS?
    FastAdmin env.sample 的用法
    可以方便配合 Git 的现代编辑器
    运算放大器复习
    Linux 权限使用 777 真的好吗?
  • 原文地址:https://www.cnblogs.com/juruo-zzt/p/13843236.html
Copyright © 2020-2023  润新知