• AHOI/HNOI2018游戏




    拓扑排序优化暴力

    复杂度证明

    啥题都要看题解,我咋这么菜!!!……

    SOL:

    我们需要预处理出两个数组(l[i],r[i],i)点到左/右最远能到达那个点,这样便于(O(1))回答询问

    当然可以左右枚举,但是为了节省时间,我们想要继承左右点可到达的信息

    于是枚举顺序就十分重要了

    ((x,x+1)),若钥匙在([1,x]),只有在([1,x])才能拓展到([x+1,n]),所以先拓展(x+1)再拓展(x),连边(x+1→x);反之同理

    用拓扑排序处理顺序,然后枚举可到达即可

    最开始加度数为0的点时从大到小,因为我们拓展时是先左端点再右端点,这样更快 我不会告诉你反过来会超时

    时间复杂度线性

    #include<bits/stdc++.h>
    using namespace std;
    inline int read(){
    	int x=0,f=1;char c=getchar();
    	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
    	while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    	return f==1?x:-x;
    }
    const int N=1e6+4;
    int n,m,Q,key[N],l[N],r[N],deg[N];
    vector<int>e[N];
    inline void calc(int x){
    	static int pl,pr;
    	pl=pr=x;
    	while(1){
    		while(pl>1&&(!key[pl-1]||(pl<=key[pl-1]&&key[pl-1]<=pr)))pl=l[pl-1];
    		while(pr<n&&(!key[pr]||(pl<=key[pr]&&key[pr]<=pr)))pr=r[pr+1];
    		if(pl==l[x]&&pr==r[x])return;
    		l[x]=pl;r[x]=pr;
    	}
    }
    inline void topsort(){
    	queue<int>q;
    	for(int i=n;i;i--)if(!deg[i])q.push(i);
    	while(!q.empty()){
    		int x=q.front();q.pop();
    		calc(x);
    		for(auto v:e[x])
    			if(!(--deg[v]))q.push(v);
    	}
    }
    int main(){
    	n=read();m=read();Q=read();
    	for(int i=1;i<=n;i++)l[i]=r[i]=i;
    	for(int i=1,x,y;i<=m;i++){
    		x=read();key[x]=y=read();
    		if(y<=x){e[x+1].push_back(x);deg[x]++;}
    		else{e[x].push_back(x+1);deg[x+1]++;}
    	}
    	topsort();
    	while(Q--){
    		static int x,y;
    		x=read();y=read();
    		if(l[x]<=y&&y<=r[x])puts("YES");
    		else puts("NO");
    	}
    	return (0-0);
    }
    
  • 相关阅读:
    那些陌生的C++关键字
    从实现装饰者模式中思考C++指针和引用的选择
    单例模式(Singleton)
    命令模式(Command)
    抽象工厂模式(Abstract Factory)
    《Effective C++》读书摘要
    桥接模式(Bridge)
    适配器模式(Adapter)
    设计模式学习心得
    黑客常用WinAPI函数整理
  • 原文地址:https://www.cnblogs.com/aurora2004/p/12581410.html
Copyright © 2020-2023  润新知