[大战div2D]Codeforces Round #816 (Div. 2) D. 2+ doors

碎碎念

看到CF已经有会打算法竞赛的AI了,不知道是不是我火星- -,据说水平约等于rating1300,知乎说“大概是一个初学OI三个月的小学生水平”
笨人去看了看自己的分数,第一次到达1300正好在初学ACM的第三个月,原来我是小学生啊(大喜
于是决定摆脱小学生称号早日上篮,开始大战cf的2D
但是马上要网络赛+四级+数学建模了也没多少时间(悲

题意: 给定\(n\)个未知数的数组\(a\)\(q\)个陈述\((i,j,x)\),表示\(a[i]\ |\ a[j]=x\),求出满足这\(q\)个陈述的最小字典序的\(a\)数组。

数据范围: $q (1≤n≤10^5, 0≤q≤2⋅10^5),(1≤i,j≤n, 0≤x<2^{30}) $

分析:由于二进制不进位,可以把每个数都拆分成二进制位来进行判断。将\(a\)的每一个数字都初始化为\(1<<30-1\),设\(a[i](k)\)表示\(a\)数组第\(i\)个数字的第\(k\)位,如果\(x(k)=0\),则直接将\(a[i](k)、a[j](k)\)置为\(0\)。如果\(x(k)=1\),则在\(a[i](k),a[j](k)\)之间连边,点权即为\(a[i](k),a[j](k)\)。对于每一个有边的点权为\(1\)的点\(p\),遍历与它有边的点\(q\),如果存在\(q=0\),则\(p\)不能为\(0\),否则\(p\)可以为\(0\)

特判:\(i=j\)时a[i]=x,否则会wa80

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define IOS ios::sync_with_stdio(false);cin.tie(0),cout.tie(0);
const int N=2e5+100;
int t,n,q,ans[N];
bool st[N];
vector<pair<int,int> > v[N];
void solve()
{
	cin>>n>>q;
	for(int i=1;i<=n;i++) ans[i]=(1<<30)-1;
	for(int i=1;i<=q;i++)
	{
		int a,b,c;cin>>a>>b>>c;
		if(a==b)
		{
			st[a]=1;
			ans[a]=c;
		}
		else
		{
			v[a].push_back({b,c});
			v[b].push_back({a,c});
			for(int j=0;j<=29;j++)
			{
				if((c>>j&1)==0)
				{
					if(ans[a]>>j&1)ans[a]-=(1<<j);
					if(ans[b]>>j&1)ans[b]-=(1<<j);
				}
			}
		}
	}

		for(int j=0;j<=29;j++)
		{
			for(int i=1;i<=n;i++)
			{
				if(st[i]) continue;
				if((ans[i]>>j&1)==0) continue;
				bool flag=1;
				for(auto p:v[i])
				{
					int k=p.first,x=p.second;
					if((x>>j&1)==0)continue;
					if((ans[k]>>j&1)==0) flag=0;
				}
				if(flag) ans[i]-=(1<<j);
			}
		}
	for(int i=1;i<=n;i++) cout<<ans[i]<<' ';
	
}

main()
{
        solve();
}

posted @ 2022-08-25 21:34  Hssliu  阅读(32)  评论(0)    收藏  举报