首页 > 其他分享 >abc155F题解

abc155F题解

时间:2024-03-14 20:57:21浏览次数:18  
标签:状态 int 题解 取反 灯泡 转化 abc155F

abc155F
题意:
给定\(n\)个灯泡的位置\(a_i\)和状态\(b_i(0/1)\)。给定\(m\)个开关控制区间\([l_i,r_i]\)中所有的灯泡,即使用这个开关会使\([l_i,r_i]\)中所有的灯泡的状态都取反。问能否使这\(n\)个灯泡的状态都变成\(0\),如果可以,输出一种方案,否则,输出\(-1\)。
思路
神仙转化题。
第一步转化,将得到\(b_i\)的异或差分数组\(c_i=\left\{\begin{matrix} b_i & i=1 \\ b_i\oplus b_{i-1} & i>1 \end{matrix}\right.\),这样区间修改就变成了对\((l_i,r_i+1)\)这个点对进行修改。
第二步转化,将点\(l_i\)和点\(r_i+1\)连一条无向边,问题就变成了在一个无向图中选一些边,对每一条被选边的两个端点的状态都取反,使最终每个点的状态都是\(0\)。
第三步转化,对于一个环上的边,这些边一定不会都被选,因为如果都选了,状态相当于没变,所以最后选出来的边组成的一定是一个森林。并且对于任意一种生成树无解,则这个无向图也一定无解。所以这里就直接找出任意一种生成树(或生成树森林),对其完成第二步转化中的任务即可。这里要注意一下有的点会与点\(n+1\)连边,这些点可以是任意状态。
代码

#include<iostream>
#include<algorithm>
using namespace std;
int kd(){
	int x=0,f=1;
	char a=getchar();
	while(a<'0'||a>'9'){
		if(a=='-'){
			f=-1;
		}
		a=getchar();
	}
	while(a>='0'&&a<='9'){
		x=x*10+a-'0';
		a=getchar();
	}
	return x*f;
}
int n,m;
struct node{
	int a,b;
}d[100010];
bool cmp(node x,node y){
	return x.a<y.a;
}
struct nod{
	int l,r;
	int p;
}c[200010];
struct nde{
	int to;
	int nxt;
	int id;
	int p;
}edge[400010];
int head[200010],tot;
void addedge(int u,int v,int id){
	edge[++tot].to=v;
	edge[tot].nxt=head[u];
	edge[tot].id=id;
	head[u]=tot;
}
int f[200010];
int cha(int u){
	while(u!=f[u]){
		u=f[u]=f[f[u]];
	}
	return u;
}
int vis[200010];
int fa[200010];
int pan[200010];
int p;
void dfs(int u){
	if(pan[u]!=0){
		p=pan[u];
	}
	vis[u]=1;
	for(int i=head[u];i;i=edge[i].nxt){
		int v=edge[i].to;
		if(vis[v]==1){
			continue;
		}
		fa[v]=i;
		dfs(v);
		if(d[v].b==1){
			edge[i].p=1;
			d[v].b=0;
			d[u].b^=1;
		}
	}
}
int main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		d[i].a=kd();d[i].b=kd();
		f[i]=i;
	}
	sort(d+1,d+n+1,cmp);
	for(int i=n;i>=2;i--){
		d[i].b^=d[i-1].b;
	}
	for(int i=1;i<=m;i++){
		c[i].l=kd();c[i].r=kd();
		int l=1,r=n;
		while(l<r){
			int mid=(l+r)/2;
			if(d[mid].a<c[i].l){
				l=mid+1;
			}
			else{
				r=mid;
			}
		}
		c[i].l=l;
		l=1;r=n;
		while(l<r){
			int mid=(l+r+1)/2;
			if(d[mid].a>c[i].r){
				r=mid-1;
			}
			else{
				l=mid;
			}
		}
		c[i].r=r;
	}
	for(int i=1;i<=m;i++){
		if(c[i].r==n){
			pan[c[i].l]=i;
			continue;
		}
		if(cha(c[i].l)!=cha(c[i].r+1)){
			addedge(c[i].l,c[i].r+1,i);
			addedge(c[i].r+1,c[i].l,i);
			f[cha(c[i].l)]=cha(c[i].r+1);
		}
	}
	for(int i=1;i<=n;i++){
		if(vis[i]==0){
			p=0;
			dfs(i);
			if(d[i].b==1){
				if(p==0){
					cout<<-1;
					return 0;
				}
				else{
					c[p].p=1;
					p=c[p].l;
					while(p!=i){
						edge[fa[p]].p^=1;
						p=edge[fa[p]%2==0?fa[p]-1:fa[p]+1].to;
					}
				}
			}
		}
	}
	for(int i=1;i<=tot;i++){
		if(edge[i].p==1){
			c[edge[i].id].p=1;
		}
	}
	int cnt=0;
	for(int i=1;i<=m;i++){
		if(c[i].p==1){
			cnt++;
		}
	} 
	cout<<cnt<<endl;
	for(int i=1;i<=m;i++){
		if(c[i].p==1){
			cout<<i<<" ";
		}
	}
	return 0;
}

标签:状态,int,题解,取反,灯泡,转化,abc155F
From: https://www.cnblogs.com/z-2-we/p/18073925

相关文章

  • CF436E - Cardboard Box 题解
    只讲贪心做法。一、反悔贪心考虑如何使选的星星总数多一。显然,有如下几种方式:选一个之前没选过的位置\(i\),答案加上\(a_i\)。选一个之前选过一次的位置\(i\),答案加上\(b_i-a_i\)。对于一个之前选过一次的位置\(i\),再找到一个没有选过的位置\(j\),反悔掉\(i\),并选......
  • 洛谷 P3596 [POI2015] MOD 题解
    题意简述给定一棵树,求断掉一条边再连上一条边所得的新树直径最小值和最大值,以及相应方案(你可以不进行任何操作,即断掉并连上同一条边)。题目分析假设我们枚举断掉某一条边,得到了两棵树,并且知道它们的直径分别为\(d_0,d_1\),那么如何连接一条边让新树的直径最大/最小呢?最大:显......
  • 洛谷 P3261 [JLOI2015] 城池攻占 题解
    题目分析其他人要么倍增,要么左偏树,那我就来讲讲朴实无华的dfs序加上线段树的做法。首先发现题目中明确指出了作乘法的时候一定是乘上一个大于零的数,这是为什么呢?首先把可以占领当前城池的战斗力的不等式列出来:\[h_j\le\left\{\begin{array}{c}s_i\timesv_j&&{a_j=......
  • 「PKUSC2022」雀圣 题解
    这边电脑的输入法要把我干烧了。。D2T3出这种模拟题,那简直不要太好。首先,不难想到暴力搜索要摸那些牌,然后丢哪些牌。然后手搓一些\(\texttt{check}\),这个应该都会,但是实际上比正解难写。我不知道\(\texttt{lay}\)打的什么东西,比我快20多倍,但是个人认为我这个思路挺暴力的。......
  • P1829 / SP8099 Crash的数字表格 题解
    P1829/SP8099Crash的数字表格题解莫比乌斯反演、数论分块、杜教筛。题目传送门题意简述求以下式子的值,对\(20101009\)(一个质数)取模:\[\sum\limits_{i=1}^n\sum\limits_{j=1}^m\operatorname{lcm}(i,j)\]\(n,m\le10^7\)。加强:\(n,m\le10^{10}\)。解法莫比乌斯反......
  • 2024-03 STEMA 考试C++ 中级真题解析
    2024-03-10STEMA考试C++中级真题解析一、选择题(50分)1、    (110010)2+(c3)16的结果是(B )。A.(240)10        B.(11110101)2        C.(366)8        D.(f6)16备注:此题目下标代表进制,因不支持md格式。  2、   表达式1000/3的结果是(......
  • 服务平滑迁移:eureka迁移到nacos。无法注册双中心的问题解决
    迁移的文档:https://www.alibabacloud.com/help/zh/edas/developer-reference/smoothly-migrate-a-spring-cloud-cluster-that-contains-multiple-applications-to-edas其中遇到的问题未配置排除配置项时(exclude={RibbonEurekaAutoConfiguration.class}),ribbonServerList不是......
  • Codeforces Round 933 (Div. 3) A - G 题解
    CodeforcesRound933(Div.3)A-RudolfandtheTicketSolution因为\(n\)很小,直接枚举\(b_i+c_j\)所产生的所有数字Code#include<bits/stdc++.h>usingnamespacestd;voidsolve(){intn,m,k;cin>>n>>m>>k;intans=0;......
  • thinkphp 5 跨域问题解决
    版本:5.1.41LTS从网上搜到好多从/public/index.php添加heade信息,或者用中间件,或者添加behavior操作,可以做到解决跨域问题,但是亲身试验了都不行,今天刚找了一个,可以使用,放在这里header('Access-Control-Allow-Credentials:true');header('Access-Control-Allow-Methods:GET,......
  • 常见问题解决 --- vmware地址分配失败
    vmware是根据分配给客户机的ip决定它处于什么网路。这句话非常抽象,我举例说明,vmware默认有三张网卡,一个桥接网卡,一个nat网卡,一个仅主机。我先说第一中情况 如果里配置客户机是桥接网卡,且在配置器中选择自动桥接。如果里宿主机有一张网卡,那么就桥接那一张网卡。并获取网路内的d......