zoukankan      html  css  js  c++  java
  • 【牛客网】小w的魔术扑克

    构造+离线+树状数组

    有一道弱化版的题:【SCOI2010】连续攻击游戏

    上面这道题,二分图最大匹配就可以了。当然这题也可以,传说中的(n^3)过1e5

    不过,这还是好妙的一道题鸭!

    part1.大致思路

    首先,对于每张牌,在(A[i])(B[i])之间连一条无向边。

    那么最后形成的图一定是由若干联通块组成的。

    不难发现,如果联通块是一棵树,显然树上有一个值是取不到的。(自己手动模拟一下吧)。

    因此,对于每个询问区间([l,r]),若([l,r])中有若干个值,它们刚好构成了一棵树,那么肯定不能构成顺子([l,r])

    所以,我们只用判断区间([l,r])中是否有若干个值构成一棵树即可。

    part2.实现与流程

    对于判断是否是一棵树,用并查集或者直接DFS都可以。

    我们取出一棵树的最大点权Mx和最小点权Mi。不难发现,若一个区间只要包含了Mx和Mi,那么这个区间显然不能为顺子。

    因此,我们可以想成:有若干条左端点为(Mi[i]),右端点为(Mx[i])的约束线段,只要一个区间([l,r])包含了至少一条约束线段,那么就是非法的。

    把右端点排个序,离线+树状数组维护就可以了。

    代码:

    #include<bits/stdc++.h>
    #define MAXN 100010
    using namespace std;
    int n,m,Q,A[MAXN],B[MAXN];
    namespace p100{
    	int cnt,head[MAXN],tot,BIT[MAXN];
    	struct node{
    		int ed,last;
    	}G[MAXN<<2];
    	bool vis[MAXN],can[MAXN];
    	vector<int> S[MAXN];
    	vector<node> P[MAXN];
    	void DFS(int x,int fa,int &Mx,int &Mi,bool &is){
    		vis[x]=true;
    		Mx=max(Mx,x);
    		Mi=min(Mi,x);
    		for(int i=head[x];i;i=G[i].last){
    			int t=G[i].ed;
    			if(t==fa)continue;
    			if(vis[t]){
    				is=false;
    				continue;
    			}
    			DFS(t,x,Mx,Mi,is);
    		}
    	}
    	void Add(int st,int ed){
    		tot++;
    		G[tot]=node{ed,head[st]};
    		head[st]=tot;
    	}
    	void ADD(int i,int x){
    		while(i<=n)BIT[i]+=x,i+=i&-i;
    	}
    	int Query(int i){
    		int res=0;
    		while(i>=1)res+=BIT[i],i-=i&-i;
    		return res;
    	}
    	void work(){
    		for(int i=1;i<=m;i++){
    			Add(A[i],B[i]);
    			Add(B[i],A[i]);
    		}
    		for(int i=1;i<=n;i++){
    			if(vis[i])continue;
    			int Mx=0,Mi=2e9+7;
    			bool is=true;
    			DFS(i,0,Mx,Mi,is);
    			if(is==true)S[Mx].push_back(Mi);
    		}
    		scanf("%d",&Q);
    		for(int i=1;i<=Q;i++){
    			int l,r;
    			scanf("%d %d",&l,&r);
    			P[r].push_back(node{l,i});
    		}
    		for(int i=1;i<=n;i++){
    			for(int j=0;j<S[i].size();j++){
    				int l=S[i][j];
    				ADD(l,1);
    			}
    			for(int j=0;j<P[i].size();j++){
    				int id=P[i][j].last,l=P[i][j].ed;
    				if(Query(i)-Query(l-1)>=1)can[id]=false;
    				else can[id]=true;
    			}
    		}
    		for(int i=1;i<=Q;i++){
    			if(can[i])puts("Yes");
    			else puts("No");
    		}
    	}
    }
    int main() {
    	scanf("%d %d",&n,&m);
    	for(int i=1; i<=m; i++)scanf("%d %d",&A[i],&B[i]);
    	p100::work();
    	return 0;
    }
    
  • 相关阅读:
    mssql 2008 数据库可疑
    sss
    css 浏览器兼容 重置代码
    .net 接口与 foreach必要条件
    .net获取ip
    flash与js的通信
    WebService传输文件的几个知识点
    【前端】深入浅出Javascript中的数值转换
    [前端]代理知识入门介绍
    Hello 博客园! ---致我人生中的第一篇随笔
  • 原文地址:https://www.cnblogs.com/SillyTieT/p/11763803.html
Copyright © 2011-2022 走看看