zoukankan      html  css  js  c++  java
  • 【洛谷6328】我是仙人掌(Floyd+bitset)

    点此看题面

    • 给定一张(n)个点(m)条边的无向图。
    • (q)次询问,每次给出(a)个二元组((x_i,y_i)),询问至少与其中一个(x_i)距离不超过(y_i)的点数。
    • (nle10^3,m,qle10^5,sum ale2.1 imes10^6)

    前言:威廉是仙人掌啊

    (bitset)处理询问

    显然对于一次询问,我们只要对每个(x_i)分别求出满足条件的点集,再给它们取个并集就可以了,具体实现可以使用(bitset)

    因此,只要对每个(x_i)求出它到所有点的距离,再把所有点和所有与它相关的二元组分别按距离排序,再只要双指针扫一遍同时维护好(bitset)即可。

    (Floyd)高光时刻

    如何求出一个点到所有点的距离?

    一个看起来复杂度无比正确的算法,就是从每个点出发跑一遍(BFS),复杂度(O(nm))。然而可能是因为我人傻常数大,终究还是(T)掉了(后来才知道,这道题卡前向星,换成(vector)结果就过了。。。)。

    这时候,我就想起一个常数极小的算法——(Floyd)

    即便它的复杂度(O(n^3))理论上极不可能通过此题,但它优秀的常数让它在实测中跑得飞快。

    P.S. 其实后来看了题解发现我根本没利用边权为(1)的性质,但反过来我这做法应该能做边权不为(1)的版本,尽管复杂度有点诡异。

    代码:(O(n^3+frac{nsum a}{32}))

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 1000
    #define M 100000
    using namespace std;
    int n,m,Qt,f[N+5][N+5];struct Q
    {
    	int p,d;I Q(CI x=0,CI y=0):p(x),d(y){}I bool operator < (Con Q& o) Con {return d<o.d;}
    };vector<Q> q[N+5];
    namespace FastIO
    {
    	#define FS 100000
    	#define tc() (FA==FB&&(FB=(FA=FI)+fread(FI,1,FS,stdin),FA==FB)?EOF:*FA++)
    	#define pc(c) (FC==FE&&(clear(),0),*FC++=c)
    	int OT;char oc,FI[FS],FO[FS],OS[FS],*FA=FI,*FB=FI,*FC=FO,*FE=FO+FS;
    	I void clear() {fwrite(FO,1,FC-FO,stdout),FC=FO;}
    	Tp I void read(Ty& x) {x=0;W(!isdigit(oc=tc()));W(x=(x<<3)+(x<<1)+(oc&15),isdigit(oc=tc()));}
    	Ts I void read(Ty& x,Ar&... y) {read(x),read(y...);}
    	Tp I void writeln(Ty x) {W(OS[++OT]=x%10+48,x/=10);W(OT) pc(OS[OT--]);pc('
    ');}
    }using namespace FastIO;
    int p;I bool cmp(CI x,CI y) {return f[p][x]<f[p][y];}//按照到p的距离排序
    int id[N+5];bitset<N+5> S,ans[M+5];I void Solve()
    {
    	S.reset(),sort(id+1,id+n+1,cmp),sort(q[p].begin(),q[p].end());vector<Q>::iterator it=q[p].begin();
    	for(RI i=1;i<=n&&it!=q[p].end()&&f[p][id[i]]<1e9;S.set(id[i++]))//距离达到INF时直接结束循环
    		if(f[p][id[i]]^f[p][id[i-1]]) W(it!=q[p].end()&&it->d==f[p][id[i-1]]) ans[it->p]|=S,++it;//维护双指针
    	W(it!=q[p].end()) ans[it->p]|=S,++it;//处理没处理完的询问
    }
    int main()
    {
    	RI i,j,k,x,y;for(read(n,m,Qt),i=1;i<=n;++i) for(j=1;j<=n;++j) f[i][j]=i^j?1e9:0;
    	for(i=1;i<=m;++i) read(x,y),x^y&&(f[x][y]=f[y][x]=1);//注意自环
    	for(k=1;k<=n;++k) for(id[k]=k,i=1;i<=n;++i) for(j=1;j<=n;++j) f[i][j]=min(f[i][j],f[i][k]+f[k][j]);//Floyd
    	for(i=1;i<=Qt;++i) for(read(k);k;--k) read(x,y),q[x].push_back(Q(i,y));//询问扔到对应点的vector中
    	for(i=1;i<=n;++i) p=i,Solve();for(i=1;i<=Qt;++i) writeln(ans[i].count());return clear(),0;//对每个点分别求解,然后输出每个询问的并集大小
    }
    
    败得义无反顾,弱得一无是处
  • 相关阅读:
    如何将cordova导入Android studio,只需两步即可
    Cordova 教程 学习步骤-从零基础开始
    特效插件
    jq 命名空间
    input聚焦后光标移动至末尾
    时间常用api
    jq 便捷api jq 常用 api jq 快捷 api
    键盘事件
    创建爬网规则
    SharePoint 2013 本地开发解决方案以及程调试(真的可以)
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/Luogu6328.html
Copyright © 2011-2022 走看看