zoukankan      html  css  js  c++  java
  • 【洛谷P5443】桥梁

    题目

    题目链接:https://www.luogu.com.cn/problem/P5443
    圣彼得堡位于由 (m) 座桥梁连接而成的 (n) 个岛屿上。岛屿用 (1)(n) 的整数编号,桥梁用 (1)(m) 的整数编号。每座桥连接两个不同的岛屿。有些桥梁是在彼得大帝时代建造的,其中一些是近期建造的。这导致了不同的桥梁可能有不同的重量限制。更具体地,只有重量不超过 (d_i) 的汽车才能通过第 (i) 座桥梁。有时圣彼得堡的一些桥梁会进行翻新,但这并不一定会使桥梁承重变得更好,也就是说,进行翻新的桥梁的 (d_i) 可能会增加或减少。你准备开发一个产品,用于帮助公民和城市客人。目前,你开发的模块要能执行两种类型的操作:

    1. 将桥梁 (b_j) 的重量限制改为 (r_j)
    2. 统计一辆重为 (w_j) 的汽车从岛屿 (s_j) 出发能够到达多少个不同的岛屿。

    请你回答所有第二种操作的答案。
    (nleq 5 imes 10^4;m,Qleq 10^5)

    思路

    吐槽:同一份代码,块长为 (sqrt{Q}) 可以获得 (4)pts 的高分,块长调到 (1400) 吸手氧就过了。
    总之就是非常卡常,同时块长 (1400) 不吸氧也只能拿到 (8)pts。虽然我实现非常垃圾,但是我还是不相信这个玩意可以在 APIO 的土豆评测机上跑过去。

    这个修改很烦,如果没有修改就是 Kruscal 重构树的傻逼题。
    对询问和操作分块,设块长为 (B),考虑如何求出一个块里的所有询问的答案。
    发现这一个块中的修改次数是 (O(B)) 的,那我们可以把不需要修改的边先搞出来,然后枚举所有询问再把这个块内的修改搞掉。
    把所有不在这个块中修改的边按照边权从大到小排序,再把这个快中的所有询问按照车的重量从大到小排序,然后依次枚举每一个询问,可以用指针扫描不需要修改的边,并把边权大于等于这次询问的车的重量的边加进并查集中。
    然后枚举这个块内的每一个修改,如果这个修改在询问的前面,并且此次修改后,询问之前,修改的这条边不会再被修改,且修改后的边权不小于车的质量,那么就把边加入并查集中。
    这样做的好处是我们对于每一个块的询问,初始边一共只会枚举 (O(m)) 次,对于每一个询问单独枚举的修改的边只有 (O(B))
    进行完一个询问后需要把区间内的修改复原,使用可撤销并查集即可实现。
    时间复杂度 (O(frac{Q}{B}mlog m+QBlog n)),理论上取 (B=sqrt{n}) 最优,实际上可能需要调调参。

    代码

    #include <bits/stdc++.h>
    #define mp make_pair
    using namespace std;
    
    const int N=100010;
    int n,n1,n2,n3,m,Q,B,U[N],V[N],D[N],id[N],father[N],siz[N],ans[N];
    bool vis[N];
    stack<pair<int,int> > st;
    
    struct Query
    {
    	int opt,x,y,id;
    }ask[N],qry[N],upd[N];
    
    bool cmp1(int x,int y)
    {
    	return D[x]<D[y];
    }
    
    bool cmp2(Query x,Query y)
    {
    	return x.y>y.y;
    }
    
    void prework()
    {
    	n1=n2=n3=0;
    	for (int i=1;i<=m;i++) vis[i]=0;
    	for (int i=1;i<=n;i++) father[i]=i,siz[i]=1;
    }
    
    int find(int x)
    {
    	return x==father[x]?x:find(father[x]);
    }
    
    void merge(int x,int y,bool flag)
    {
    	if (x==y) return;
    	if (siz[x]>siz[y]) swap(x,y);
    	father[x]=y; siz[y]+=siz[x];
    	if (flag) st.push(mp(x,y));
    }
    
    int main()
    {
    	B=1400;
    	scanf("%d%d",&n,&m);
    	for (int i=1;i<=m;i++)
    		scanf("%d%d%d",&U[i],&V[i],&D[i]);
    	scanf("%d",&Q);
    	for (int i=1;i<=Q;i++)
    	{
    		scanf("%d%d%d",&ask[i].opt,&ask[i].x,&ask[i].y);
    		ask[i].id=i;
    	}
    	for (int i=1;i<=Q/B+1;i++)
    	{
    		prework();
    		int L=(i-1)*B+1,R=min(i*B,Q);
    		for (int j=L;j<=R;j++)
    			if (ask[j].opt==1)
    				upd[++n1]=ask[j],vis[ask[j].x]=1;
    			else
    				qry[++n2]=ask[j];
    		for (int j=1;j<=m;j++)
    			if (!vis[j]) id[++n3]=j;
    		sort(id+1,id+1+n3,cmp1);
    		sort(qry+1,qry+1+n2,cmp2);
    		for (int j=1,k=n3;j<=n2;j++)
    		{
    			for (int l=1;l<=n1;l++) vis[upd[l].x]=1;
    			for (;k && D[id[k]]>=qry[j].y;k--)
    				merge(find(U[id[k]]),find(V[id[k]]),0);
    			for (int l=n1;l>=1;l--)
    				if (upd[l].id<qry[j].id && vis[upd[l].x])
    				{
    					vis[upd[l].x]=0;
    					if (upd[l].y>=qry[j].y)
    						merge(find(U[upd[l].x]),find(V[upd[l].x]),1);
    				}
    			for (int l=1;l<=n1;l++)
    				if (vis[upd[l].x])
    				{
    					vis[upd[l].x]=0;
    					if (D[upd[l].x]>=qry[j].y)
    						merge(find(U[upd[l].x]),find(V[upd[l].x]),1);
    				}
    			ans[qry[j].id]=siz[find(qry[j].x)];
    			for (;st.size();st.pop())
    			{
    				int x=st.top().first,y=st.top().second;
    				siz[y]-=siz[x]; father[x]=x;
    			}
    		}
    		for (int j=1;j<=n1;j++)
    			D[upd[j].x]=upd[j].y;
    	}
    	for (int i=1;i<=Q;i++)
    		if (ans[i]) printf("%d
    ",ans[i]);
    	return 0;
    }
    
  • 相关阅读:
    Matlab 绘制三维立体图(以地质异常体为例)
    Azure DevOps的variable group实现array和hashtable参数的传递
    Azure DevOps 利用rest api设置variable group
    Azure AADSTS7000215 其中一种问题的解决
    Power BI 实现实时更新Streaming Dataset
    AAD Service Principal获取azure user list (Microsoft Graph API)
    Matlab 沿三维任意方向切割CT图的仿真计算
    Azure Powershell script检测登陆并部署ARM Template
    Azure KeyVault设置策略和自动化添加secrets键值对
    Azure登陆的两种常见方式(user 和 service principal登陆)
  • 原文地址:https://www.cnblogs.com/stoorz/p/14802619.html
Copyright © 2011-2022 走看看