把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

【BZOJ3563】DZY Loves Chinese(挖坟:长达20个月的坑)

点此看题面

大致题意: 一张无向图。每次询问给出一行,第一个数\(k\),以及接下来\(k\)个数表示边的编号,要求回答删去这\(k\)条边后图是否联通。强制在线,每次询问的\(k\)及其后\(k\)个数全都要异或上之前回答连通的次数。

前言

挖坟祭。。。

【洛谷5236】【模板】静态仙人掌(圆方树板子)这道题之后又一次写掉一道咕了超过一年的题目。

然而上面那题还只是咕了\(14\)个月,这道题居然咕了\(20\)个月。。。

为什么会突然想到写这道题呢?

这则是因为做了这道题:【BZOJ3214】[ZJOI2013] 丽洁体(毒瘤字符串读入+动态规划水题)。然后我就自认为现在应该能更好地处理此类和读入有关的问题。

我先找到了原先的代码,然后发现以前的码风和现在截然不同(原先那些变量名定义得超长无比,而且那时似乎还处于我不压行与压行的过渡时期,因此十分清奇),于是恶改了一阵码风。

好不容易改完了码风,然后。。。

就过了?!

又仔细去看了一遍发现原来的代码甚至连样例都没过!(样例都没过我居然敢交,我真佩服过去自己的胆量。。。)

接下来好好研读了一遍原先的代码,发现有一个写得十分丑陋怪异的地方很智障地写挂了,而我改码风时看它不顺眼就把它拍扁+重构了一遍,于是就歪打正着地对了。。。

乱搞

此题是道乱搞题,正经做法请见另一道题:【BZOJ3569】DZY Loves Chinese II

好好看看题目中给出的强制在线方式, 就会发现它居然把每次询问的\(k\)也异或了!

于是我们就会有一个乱搞的想法:每次读入它给出的\(k'\),然后求出实际数的个数\(k\),就会发现\(k'\ xor\ k\)即为之前回答连通的个数,只要差分一下就能求出上次的答案!

然后我们只要\(O(n)\)并查集暴力搞一下最后一个询问,于是这道题就做完了。。。

具体实现详见代码。

代码

#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 100000
#define M 500000
#define LL long long
#define INF 1e9
using namespace std;
int n,m,a[20],fa[N+5],del[M+5];struct edge {int x,y,nxt,pos;}e[M+5];
I bool read(int& x)//读入,实际上类似于读优
{
	#define D isdigit(c)
	static char c=getchar();W(!D) {if(c=='\n'||c==EOF) return c=getchar(),0;c=getchar();}//如果读到回车或终止符
	x=0;W(D) x=(x<<3)+(x<<1)+(c&15),c=getchar();return 1;
}
I int getfa(CI x) {return fa[x]^x?fa[x]=getfa(fa[x]):x;}
int main()
{
	RI Qt,i,x,y,s,t,ans=0,f=1,fx,fy;
	for(scanf("%d%d",&n,&m),i=1;i<=m;++i) scanf("%d%d",&x,&y),e[i].x=x,e[i].y=y;//读入边
	for(scanf("%d",&Qt);Qt;--Qt)//处理询问
	{
		W(!read(s));t=0;W(read(a[++t]));--t;//读入这一行的数,注意个数减1,因为最后一个读失败的数不能算在内
		f?f=0:(s^t^ans?(puts("Connected"),ans=s^t):puts("Disconnected"));
		//若当前不是第一个询问,如果回答连通次数与之前不同,说明上次回答连通,否则上次回答不连通
	}
	//接下来是暴力
	for(i=1;i<=t;++i) del[a[i]^ans]=1;for(i=1;i<=n;++i) fa[i]=i;//标记被删的边,预处理并查集
	for(i=1;i<=m;++i) !del[i]&&(fx=getfa(e[i].x))^(fy=getfa(e[i].y))&&(fa[fy]=fx);//对于没被删的边,合并连通块
	for(getfa(1),i=2;i<=n;++i) if(getfa(i)^fa[1]) return puts("Disconnected"),0;//判断是否连通
	return puts("Connected"),0;
}
posted @ 2020-05-17 18:27  TheLostWeak  阅读(178)  评论(0编辑  收藏  举报